Отметить параметры как не обнуляемые в C # /. NET? - PullRequest
84 голосов
/ 14 ноября 2008

Существует ли простой атрибут или контракт данных, который я могу назначить параметру функции, который предотвращает передачу null в C # /. NET? В идеале это также проверяет во время компиляции, чтобы убедиться, что литерал null нигде для него не используется, и во время выполнения throw ArgumentNullException.

В настоящее время я пишу что-то вроде ...

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

... для каждого аргумента, который, как я ожидаю, не будет null.

На той же ноте, есть ли противоположность Nullable<>, в результате чего следующее не получится:

NonNullable<string> s = null; // throw some kind of exception

Ответы [ 6 ]

64 голосов
/ 14 ноября 2008

К сожалению, во время компиляции ничего не доступно.

У меня есть немного хакерского решения , которое я недавно опубликовал в своем блоге, которое использует новую структуру и преобразования.

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

У меня также есть метод расширения в MiscUtil , который называется ThrowIfNull, что делает его немного проще.

И последнее замечание - есть ли причина использовать "if (null == arg)" вместо "if (arg == null)"? Я считаю, что последнее легче читать, и проблема, которую первый решает в C, не относится к C #.

15 голосов
/ 08 марта 2013

Я знаю, что это ОЧЕНЬ старый вопрос, но здесь его не было:

Если вы используете ReSharper, вы можете использовать Annotated Framework .

12 голосов
/ 08 февраля 2018

Я знаю, что невероятно опоздал на этот вопрос, но я чувствую, что ответ станет актуальным, так как последняя крупная итерация C # приближается к выпуску, а затем к выпуску. В C # 8.0 произойдет серьезное изменение, C # будет предполагать, все типы считаются ненулевыми.

По словам Мадс Торгерсен:

Проблема в том, что нулевые ссылки так полезны. В C # они являются значение по умолчанию для каждого ссылочного типа. Что еще будет по умолчанию значение будет? Какое другое значение будет иметь переменная, пока вы не сможете решить что еще ему назначить? Какую другую ценность мы могли бы проложить недавно распределенный массив ссылок закончен, пока вы не найдете время заполнить его?

Кроме того, иногда ноль - разумная ценность сама по себе. Иногда Вы хотите представить тот факт, что, скажем, поле не имеет значение. То, что можно передать «ничего» для параметра. Акцент хотя иногда. И в этом заключается другая часть проблемы: Такие языки, как C #, не позволяют вам выразить, является ли значение NULL прямо здесь хорошая идея или нет.

Итак, разрешение, обозначенное Мэдсом, составляет:

  1. Мы считаем, что более распространенным является требование, чтобы ссылка не была нулевой. Обнуляемые ссылочные типы будет более редким видом (хотя у нас нет хороших данных, чтобы сообщить нам сколько), поэтому именно они должны требовать новой аннотации.

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

  3. Кажется правильным, что вы не должны обременять себя или своего потребителя громоздкими нулевыми значениями, если вы активно не решили, что вы хочу их. Нули, а не их отсутствие, должны быть Вы явно должны выбрать.

Пример желаемой функции:

public class Person
{
     public string Name { get; set; } // Not Null
     public string? Address { get; set; } // May be Null
}

Предварительный просмотр доступен для Visual Studio 2017, предварительный просмотр 15.5.4+.

9 голосов
/ 15 ноября 2008

Проверьте валидаторы в корпоративной библиотеке. Вы можете сделать что-то вроде:

private MyType _someVariable = TenantType.None;
[NotNullValidator(MessageTemplate = "Some Variable can not be empty")]
public MyType SomeVariable {
    get {
        return _someVariable;
    }
    set {
        _someVariable = value;
    }
}

Тогда в вашем коде, когда вы хотите проверить его:

Microsoft.Practices.EnterpriseLibrary.Validation.Validator myValidator = ValidationFactory.CreateValidator<MyClass>();

ValidationResults vrInfo = InternalValidator.Validate(myObject);
0 голосов
/ 05 октября 2011

Хорошо, этот ответ немного запоздал, но вот как я его решаю:

public static string Default(this string x)
{
    return x ?? "";
}

Используйте этот метод расширения, тогда вы можете рассматривать пустую и пустую строки как одно и то же.

например.

if (model.Day.Default() == "")
{
    //.. Do something to handle no Day ..
}

Не идеально, я знаю, вы должны помнить, чтобы вызывать default везде, но это одно решение.

0 голосов
/ 05 апреля 2011

не самая красивая, но:

public static bool ContainsNullParameters(object[] methodParams)
{
     return (from o in methodParams where o == null).Count() > 0;
}

Вы также можете проявить креативность в методе ContainsNullParameters:

public static bool ContainsNullParameters(Dictionary<string, object> methodParams, out ArgumentNullException containsNullParameters)
       {
            var nullParams = from o in methodParams
                             where o.Value == null
                             select o;

            bool paramsNull = nullParams.Count() > 0;


            if (paramsNull)
            {
                StringBuilder sb = new StringBuilder();
                foreach (var param in nullParams)
                    sb.Append(param.Key + " is null. ");

                containsNullParameters = new ArgumentNullException(sb.ToString());
            }
            else
                containsNullParameters = null;

            return paramsNull;
        }

конечно, вы можете использовать перехватчик или отражение, но за ними легко следить / использовать с небольшими накладными расходами

...