Обнулить несколько параметров и выдать исключение с их именем - PullRequest
3 голосов
/ 06 марта 2019

Я хотел бы проверить несколько параметров и выдать ArgumentNullException, если любой из них равен null.Ради аргумента, давайте предположим, что у меня есть это:

public void DoSomething(SomeClass param1, SomeClass param2, SomeClass param3);

Конечно, я мог бы сделать:

if (param1 == null)
    throw new ArgumentNullException(nameof(param1));
if (param2 == null)
    throw new ArgumentNullException(nameof(param2));
if (param3 == null)
    throw new ArgumentNullException(nameof(param3));

Но это не особенно красиво, особенно если это повторяющеесяпроверить на протяжении всего приложения.Итак, я думал, что сделаю это:

public static class ValidationExtensions
{
    public static void NullCheck<T>(this T subject)
    {
        if (T == null)
            throw new ArgumentNullException();
    }
}

// ...

param1.NullCheck();
param2.NullCheck();
param3.NullCheck();

Но так я потеряю nameof.Я не могу сделать nameof(subject), поскольку это бессмысленно.

Конечно, это вариант:

public static class ValidationExtensions
{
    public static void NullCheck<T>(this T subject, string parameterName)
    {
        if (T == null)
            throw new ArgumentNullException(parameterName);
    }
}

// ...

param1.NullCheck(nameof(param1));
param2.NullCheck(nameof(param2));
param3.NullCheck(nameof(param3));

Но, похоже, он подвержен ошибкам с повторяющимися параметрами ... иЕсли честно, просто не красиво.

Есть ли хороший способ сделать это?В идеале без использования каких-либо внешних библиотек.

Ответы [ 2 ]

1 голос
/ 06 марта 2019

Наиболее кратким и понятным решением будет то, что у вас есть, или C # 7 Бросающее выражение

param1 = param1 ?? throw new ArgumentNullException(nameof(param1));

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

Тем не менее, помимо всего этого, я даю вам выражений

public static class Validator
{
   public static void Validate<T>(Expression<Func<string, T>> f)
   {
      var name = (f.Body as MemberExpression).Member.Name;
      if(f.Compile().Invoke(name) == null)
         throw new ArgumentNullException(name);    
   }
}

Причина, по которой это работает, заключается в том, что компилятор генерирует класс для лямбда-выражения (замыкание), а локальная переменная становится свойством Member.Name, что означает, что оно также должно работать и для свойств (не проверено)

Использование

public static void Test(string param1, string param2)
{
   Validator.Validate(x => param1);
}

public static void Main()
{
   Test(null,"asdf");
}

Выход

Значение не может быть нулевым.Имя параметра: param1

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

0 голосов
/ 06 марта 2019

Остерегайтесь этих "оптимизаций кода". Деревья отражений и выражений идут с потерей производительности.

Даже ваш вариант дженериков заставляет разработчика использовать его излишне. По крайней мере, добавьте к нему ограничение:

public static void NullCheck<T>(this T subject, string parameterName) where T : class

Конечно, это тоже не бесплатно.

С введением throw в качестве выражения в C # 7.0 (как Майкл Рэндалл показал в своем ответе ) это один лайнер и Visual Studio сделает это за вас.

...