Отметить параметры как НЕВОЗМОЖНЫЕ в С#/. NET?

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

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

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

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

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

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

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

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

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

  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+.

Ответ 3

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

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

Изменить: я только что получил случайный -1 для этого ответа. Это хорошо. Просто имейте в виду, что он по-прежнему действителен, даже если он больше не рекомендуется для проектов на С# 8. 0+ (чтобы понять почему, см. Greg answer).

Ответ 4

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

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);

Ответ 5

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

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;
        }

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

Ответ 6

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

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

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

например.

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

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

Ответ 7

public void foo(int? id, string name)
{
    if (id == null)
    {
       throw new ArgumentNullException("id");
    }
    if (name == null)
    {
       throw new ArgumentNullException("name");
    }

    this.foo = id.Value;
    this.fooName = name;
}

Там вы идете, иначе просто определите другое утверждение.