null-CHAMECK多个参数,并以其名称进行异常



我想验证多个参数,如果其中任何一个是 null,则将ArgumentNullException丢弃。为了论证,让我们假设我已经知道了:

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

,但似乎很容易出错,带有重复的参数...老实说,只是不漂亮。

有没有很好的方法?理想情况下,不使用任何外部库。

最简洁和可维护的解决方案是您拥有的,或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);    
   }
}

这起作用的原因是因为编译器生成了lambda表达式的类(闭合),而本地变量变为属性Member.Name,这意味着它也应该适用于属性(未测试)

用法

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

输出

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

注意:说实话,我没有考虑过太多或对几个用例进行测试,它可能会或可能不起作用,因此我对此不负责您对此代码受伤的人

.NET 6 (C# 10)中您可以使用gonge nullexception.throwifnull。

ArgumentNullException.ThrowIfNull(param1, nameof(param1));
ArgumentNullException.ThrowIfNull(param2, nameof(param2));
ArgumentNullException.ThrowIfNull(param3, nameof(param3));

尚无多个参数的选项,但是您可以添加以下助手:

public static class ArgumentNullExceptionHelpers
{
    public static void ThrowIfNull(params object[] arguments)
    {
        ArgumentNullException.ThrowIfNull(arguments);
        foreach (object argument in arguments)
        {
            ArgumentNullException.ThrowIfNull(argument);
        }
    }
    public static void ThrowIfNull(
        params (object? Argument, string ParamName)[] value)
    {
        foreach ((object? argument, string paramName) in value)
        {
            ArgumentNullException.ThrowIfNull(argument, paramName);
        }
    }
}

,然后称其为:

ArgumentNullExceptionHelpers.ThrowIfNull(param1, param2, param3);
// Or - with argument names
ArgumentNullExceptionHelpers.ThrowIfNull(
    (param1, nameof(param1)), (param2, nameof(param2)), (param3, nameof(param3)));

当心那些"代码优化"。反射和表达树带有性能惩罚。

即使是您的通用选项,也会使开发人员不必要地使用它。至少对此添加约束:

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

当然,这也不是免费的。

随着throw作为 c#7.0 的表达式(正如Michael Randall在他的回答中显示的那样),这是一个衬里,视觉工作室将为您做到这一点。

相关内容

  • 没有找到相关文章

最新更新