对多个参数进行空检查并使用其名称引发异常

use*_*505 7 c# validation nameof

我想验证多个参数并抛出一个ArgumentNullException如果其中任何一个null。为了便于讨论,我们假设我有这个:

public void DoSomething(SomeClass param1, SomeClass param2, SomeClass param3);
Run Code Online (Sandbox Code Playgroud)

当然,我可以这样做:

if (param1 == null)
    throw new ArgumentNullException(nameof(param1));
if (param2 == null)
    throw new ArgumentNullException(nameof(param2));
if (param3 == null)
    throw new ArgumentNullException(nameof(param3));
Run Code Online (Sandbox Code Playgroud)

但它并不是特别漂亮,特别是如果它是在整个应用程序中反复检查的话。所以,我想我会这样做:

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

// ...

param1.NullCheck();
param2.NullCheck();
param3.NullCheck();
Run Code Online (Sandbox Code Playgroud)

但这样我就失去了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));
Run Code Online (Sandbox Code Playgroud)

但由于参数重复,它似乎很容易出错……而且,说实话,不太漂亮。

有没有一个好的方法来做到这一点?理想情况下不使用任何外部库。

AAA*_*ddd 4

最简洁和可维护的解决方案就是您所拥有的,或者 C#7 Throw Expression

param1 = param1 ?? throw new ArgumentNullException(nameof(param1));
Run Code Online (Sandbox Code Playgroud)

您可以使用表达式和一些智能,尽管我不推荐这样做,它的味道并隐藏在抽象开销背后的简单逻辑。此外,它依赖于未来可能发生变化的未指定行为

然而,除此之外,我给你表达

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);    
   }
}
Run Code Online (Sandbox Code Playgroud)

这样做的原因是因为编译器为 lambda 表达式(闭包)生成一个类,并且局部变量成为一个属性Member.Name,这意味着它也应该适用于属性(未经测试)

用法

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

public static void Main()
{
   Test(null,"asdf");
}
Run Code Online (Sandbox Code Playgroud)

输出

值不能为空。参数名称:param1

注意:说实话,我没有对此考虑太多,也没有对它进行超过几个用例的测试,它可能会也可能不会起作用,所以我不对你用这段代码伤害的人负责