Рефакторинг Guard Clauses

Какие подходы люди используют (если они есть) для управления взрывом guard в ваших классах? Например:

public void SomeMethod<T>(string var1, IEnumerable<T> items, int count)
{
    if (string.IsNullOrEmpty(var1))
    {
        throw new ArgumentNullException("var1");
    }

    if (items == null)
    {
        throw new ArgumentNullException("items");
    }

    if (count < 1)
    {
        throw new ArgumentOutOfRangeException("count");
    }

    ... etc ....
}

В проекте, над которым я сейчас работаю, есть много классов с аналогичным набором защитных предложений для публичных методов.

Я знаю о кодовых контрактах .NET 4.0, однако в данный момент это не вариант для нашей команды.


person Kane    schedule 20.10.2009    source источник


Ответы (5)


Многие проекты, которые я видел, используют статический класс Guard.

public static class Guard {
    public static void ArgumentIsNotNull(object value, string argument) {
        if (value == null)
            throw new ArgumentNullException(argument);
    }
}

На мой взгляд, это делает код намного чище.

Guard.ArgumentIsNotNull(arg1, "arg1");
person David Brown    schedule 20.10.2009
comment
Я просто публиковал то же самое. Единственная проблема заключается в том, что он помещает этот метод наверху трассировки стека по сравнению с исходным методом наверху, а не в том, что он такой уж огромный. Этот шаблон, очевидно, может использоваться для разных типов для проверки диапазона значений и т. д. - person Wil P; 21.10.2009
comment
Да, это единственная проблема, с которой я когда-либо сталкивался. Хотя найти исходный метод вызова достаточно просто. - person David Brown; 21.10.2009
comment
По сути, это то же самое, что и классы, имитирующие кодовые контракты. - person Robert Harvey; 21.10.2009
comment
только что использовал это. Спасибо! Первая строка должна быть общедоступной статической защитой класса, а не общедоступной статической защитой. - person Korey; 25.08.2011
comment
Я бы посоветовал вам аннотировать методы защиты с помощью файла [DebuggerHiddenAttribute]. Это гарантирует, что отладчик не остановится на этих методах, а вернется к исходному методу. См. msdn.microsoft.com/en-us/library/ Если вы используете ReSharper, вы также можете аннотировать методы защиты с помощью [ContractAnnotationAttribute], а параметр argument можно аннотировать с помощью [InvokerParameterName], что дает вам интеллигентность для строк имени параметра. - person Siewers; 31.01.2013
comment
@TigerShark, ты чертовски крут. - person georgiosd; 30.01.2014
comment
@TigerShark [DebuggerHiddenAttribute] был именно той недостающей частью, которая мешала мне использовать помощника Guard. Спасибо!! - person Jaanus Varus; 16.10.2014

Если вы не хотите идти по маршруту Code Contracts, один из способов упростить его — удалить фигурные скобки:

public void SomeMethod<T>(string var1, IEnumerable<T> items, int count)
{
    if (string.IsNullOrEmpty(var1))
        throw new ArgumentNullException("var1");

    if (items == null)
        throw new ArgumentNullException("items");

    if (count < 1)
        throw new ArgumentOutOfRangeException("count");

    ... etc ....
}

Помимо этого, есть несколько способов имитации кодовых контрактов, если вы возражаете против того, что .Net 4.0 еще не в прайм-тайм:

http://geekswithblogs.net/Podwysocki/archive/2008/01/22/118770.aspx

person Robert Harvey    schedule 20.10.2009
comment
Ради бога, не делай этого! Операторы if без фигурных скобок — отличный способ создать себе проблемы в будущем. - person EricRRichards; 27.02.2018
comment
Остерегайтесь этого! Печально известный goto fail был дорогостоящим результатом отсутствия фигурных скобок. (полное раскрытие: иногда я не использую фигурные скобки, но только если все это помещается в одну строку) - person Rufus L; 13.02.2019
comment
@RufusL: Это произошло на языке программирования, печально известном тем, что в нем нет таких систем безопасности, как в C#. Ни один уважающий себя программист никогда не будет использовать goto в программе на C#. - person Robert Harvey; 13.02.2019
comment
О какой системе безопасности вы говорите? - person Rufus L; 13.02.2019
comment
@RufusL: О скольких ты хочешь знать? Управление памятью, защита диапазона, обработка исключений, песочница IL... Продолжать? - person Robert Harvey; 13.02.2019
comment
Я думал, что вы имеете в виду что-то, что применимо к кому-то, добавляющему дополнительную строку после оператора if, например, к ошибке goto fail, и я не мог придумать ни одной функции языка/компилятора, которая предотвратила бы это. Определенно согласен с вами в том, что вы не используете goto. - person Rufus L; 13.02.2019

Вы можете подумать о рефакторинге, чтобы ввести нулевой объект.

person Todd Stout    schedule 21.10.2009

Между тем, есть отличная статья об этом здесь: nofollow">http://haacked.com/archive/2013/01/05/mitigate-the-billion-dollar-mistake-with-aspects.aspx/

Я бы подумал об использовании NullGuard.Fody, так как я в восторге от возможностей Fody по сокращению шаблонного кода.

person mamuesstack    schedule 07.02.2015

Один из подходов к сокращению (но не полному удалению) количества защитных предложений состоит в том, чтобы понять причину их существования. Довольно часто оказывается, что мы защищаемся от значений, которые допустимы для типа аргумента, но недействительны для метода, который их принимает. Другими словами, метод определяется в подмножестве домена, определяемого типом аргумента.

Решение этой категории случаев состоит в том, чтобы попытаться определить подтип (например, более строгий интерфейс) и принять этот тип в качестве аргумента. Наглядный пример вы можете найти в этой статье: Почему Нам нужны защитные оговорки?

Конечно, этот метод применим не ко всем случаям. Все ссылочные типы, по крайней мере, допускают пустые ссылки. Следовательно, большинство наших методов будут определены в части предметной области, что, в свою очередь, требует защитного предложения от null.

Но с положительной стороны, этот метод помогает повысить осведомленность о методах, которые получают аргументы, которые являются более общими, чем хотелось бы. Заделка этого отверстия помогает улучшить дизайн в целом.

person Zoran Horvat    schedule 19.08.2015