首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ArgumentNullException -如何简化?

ArgumentNullException -如何简化?
EN

Stack Overflow用户
提问于 2012-08-21 03:28:52
回答 15查看 15.5K关注 0票数 20

我注意到这段代码在我的构造函数中出现得很多:

代码语言:javascript
复制
if (someParam == null) throw new ArgumentNullException("someParam");
if (someOtherParam == null) throw new ArgumentNullException("someOtherParam");
...

我有几个构造器,其中有几个东西被注入,并且必须都是非空的。有没有人能想出一种方法来简化这个过程?我唯一能想到的是:

代码语言:javascript
复制
public static class ExceptionHelpers
{
   public static void CheckAndThrowArgNullEx(IEnumerable<KeyValuePair<string, object>> parameters)
   {
      foreach(var parameter in parameters)
         if(parameter.Value == null) throw new ArgumentNullException(parameter.Key);
   }
}

但是,它的用法如下所示:

代码语言:javascript
复制
ExceptionHelper.CheckAndThrowArgNullEx(new [] {
    new KeyValuePair<string, object>("someParam", someParam),
    new KeyValuePair<string, object>("someOtherParam", someOtherParam),
    ... });

..。这对简化代码并没有真正的帮助。Tuple.Create()而不是KVP无法工作,因为元组的GTP不是协变的(即使IEnumerable的GTP是协变的)。有什么想法吗?

EN

回答 15

Stack Overflow用户

回答已采纳

发布于 2012-08-21 04:41:32

对于你们中的大多数人来说,你们的回答有助于我最终得出的解决方案,它包含了一些零碎的东西,但最终都是不同的。

我创建了两个静态方法,用于处理特定形式的lambda表达式(编辑-小更改;这些方法不能是泛型的,否则它们将要求所有表达式返回相同的类型。Func是好的,在GetName方法中有一个额外的条件来解开类型转换):

代码语言:javascript
复制
public static class ExpressionReader
{
    /// <summary>
    /// Gets the name of the variable or member specified in the lambda.
    /// </summary>
    /// <param name="expr">The lambda expression to analyze. 
    /// The lambda MUST be of the form ()=>variableName.</param>
    /// <returns></returns>
    public static string GetName(this Expression<Func<object>> expr)
    {
        if (expr.Body.NodeType == ExpressionType.MemberAccess)
            return ((MemberExpression) expr.Body).Member.Name;

        //most value type lambdas will need this because creating the 
        //Expression from the lambda adds a conversion step.
        if (expr.Body.NodeType == ExpressionType.Convert
                && ((UnaryExpression)expr.Body).Operand.NodeType 
                     == ExpressionType.MemberAccess)
            return ((MemberExpression)((UnaryExpression)expr.Body).Operand)
                   .Member.Name;

        throw new ArgumentException(
           "Argument 'expr' must be of the form ()=>variableName.");
    }
}

public static class ExHelper
{
    /// <summary>
    /// Throws an ArgumentNullException if the value of any passed expression is null.
    /// </summary>
    /// <param name="expr">The lambda expressions to analyze. 
    /// The lambdas MUST be of the form ()=>variableName.</param>
    /// <returns></returns>
    public static void CheckForNullArg(params Expression<Func<object>>[] exprs)
    {
        foreach (var expr in exprs)
            if(expr.Compile()() == null)
                throw new ArgumentNullException(expr.GetName());
    }
}

..。它可以这样使用:

代码语言:javascript
复制
//usage:

ExHelper.CheckForNullArg(()=>someParam, ()=>someOtherParam);

这将样板文件减少到一行,而不需要第三方工具。ExpressionReader和异常生成方法都适用于在调用方中编译的()=>variableName形式的任何lambda,这意味着它至少适用于局部变量、参数、实例字段和实例属性。我还没有检查它在静态上是否有效。

票数 5
EN

Stack Overflow用户

发布于 2012-08-21 03:56:35

C# 7的更新

您可以将throw expression与null合并运算符一起使用。下面是该页面中一个示例:

代码语言:javascript
复制
public string Name
{
    get => name;
    set => name = value ?? 
        throw new ArgumentNullException(paramName: nameof(value), message: "New name must not be null");
}

原始答案

就我个人而言,我使用ThrowIfNull扩展方法。我不知道该归功于谁,但我肯定是didn't invent it。这很好,因为你可以用返回值进行赋值:

代码语言:javascript
复制
public static T ThrowIfNull<T>(this T argument, string argumentName)
{
    if (argument == null)
    {
        throw new ArgumentNullException(argumentName);
    }
    return argument;
}

用法:

代码语言:javascript
复制
this.something = theArgument.ThrowIfNull("theArgument");
// or in C# 6
this.something = theArgument.ThrowIfNull(nameof(theArgument));

(尽管有些人认为在空实例上调用扩展方法很奇怪)

如果你真的想一次检查多个参数,如果你像这样使用一个params签名,你的例子可能会更流畅:

代码语言:javascript
复制
public static void CheckAndThrowArgNullEx(params object[] argsAndNames)
{
    for (int i = 0; i < argsAndNames.Length; i += 2)
    {
        if (argsAndNames[i] == null)
        {
            string argName = (string)argsAndNames[i + 1];
            throw new ArgumentNullException(argName);
        }
    }
}

它的用法是:

代码语言:javascript
复制
CheckAndThrowArgNullEx(arg1, "arg1", arg2, "arg2");
// or in C# 6
CheckAndThrowArgNullEx(arg1, nameof(arg1), arg2, nameof(arg2));

再三考虑,正如KeithS在评论中提到的那样,将其实现为一组重载可能比像这样使用params object[]更好:

代码语言:javascript
复制
static void Check(object arg1, string arg1Name) { ... }
static void Check(object arg1, string arg1Name, object arg2, string arg2Name) { ... }
// and so on...
票数 24
EN

Stack Overflow用户

发布于 2018-03-07 01:03:00

试试这个:一行。

代码语言:javascript
复制
accounts = accounts ?? throw new ArgumentNullException(nameof(accounts));

此外,使用nameof(),如果变量被重命名,你将不必寻找所有的“变量”,让nameof()来做。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12043875

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档