ArgumentNullException-如何简化?我注意到这段代码在我的构造函数中出现了很多:if(someParam==null)thrownewArgumentNullException("someParam");if(someOtherParam==null)thrownewArgumentNullException("someOtherParam");...我有一些构造函数,其中注入了一些东西并且必须都是非空的。任何人都可以想出一种方法来简化这个吗?我唯一能想到的是以下内容:钥匙);然而,使用它看起来像这样:...这并没有真正帮助简化代码。Tuple.Create()而不是KVP不起作用,因为Tuple的GTP不是协变的(即使IEnumerable的GTP是协变的)。有任何想法吗?C#7的更新您可以将throw表达式与null合并运算符结合使用。这是该页面的示例:publicstringName{get=>name;设置=>名称=值??thrownewArgumentNullException(paramName:nameof(value),message:"Newnamemustnotbenull");}原始答案就我个人而言,我使用ThrowIfNull扩展方法。我不知道该归功于谁,但绝对不是我发明的。这很好,因为您可以使用返回值进行赋值:}返回参数;用法:这个。something=theArgument.ThrowIfNull("theArgument");//或者在C#6中this.something=theArgument.ThrowIfNull(nameof(theArgument));(虽然有些人认为在null实例上调用扩展方法很奇怪)如果你真的想一次检查多个参数,如果你使用params签名,那么你的例子可以更精简:publicstaticvoidCheckAndThrowArgNullEx(paramsobject[]argsAndNames){for(inti=0;iusageis:CheckAndThrowArgNullEx(arg1,"arg1",arg2,"arg2");//或者在C#6CheckAndThrowArgNullEx(arg1,nameof(arg1),arg2,nameof(arg2));第二个想法,正如KeithS在评论中提到的那样,将它实现为一组重载而不是像这样使用paramsobject[]可能更好:staticvoidCheck(objectarg1,stringarg1Name){...}staticvoidCheck(objectarg1,stringarg1Name,objectarg2,stringarg2Name){...}//等等...有几种方法可以解决这个问题。选项A:将您的函数分成两部分-验证和实现(你可以在JonSkeet的EduLinq这个例子中看到这个)。选项B:使用期望参数为非空的代码协定。选项C:使用代码编织等面向方面的技术将这些检查提取到一个方面。(正如JTorres回答的那样)。选项D:使用Spec#,正如CodeInChaos评论的那样。选项E:???大多数人的上涨;您的回答对我最终得到的解决方案有所帮助,该解决方案包含点点滴滴,但最终与所有这些都不同。我创建了一些处理特定形式的lambda表达式的静态方法(编辑-小改动;方法不能是通用的,或者它们要求所有表达式返回相同的类型。Func很好,GetName方法有一个额外的条件):publicstaticclassExpressionReader{//////获取lambda中指定的变量或成员的名称。//////要分析的lambda表达式。///lambda必须是()=>variableName的形式。///publicstaticstringGetName(thisExpression>expr){if(expr.Body.NodeType==ExpressionType.MemberAccess)return((MemberExpression)expr.Body).Member.Name;//大多数值类型的lambda都需要这个,因为从lambda创建//Expression会添加一个转换步骤。如果(expr.Body.NodeType==ExpressionType.Convert&&((UnaryExpression)expr.Body).Operand.NodeType==ExpressionType.MemberAccess)返回((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.姓名;thrownewArgumentException("参数'expr'的形式必须为()=>variableName。");}}publicstaticclassExHelper{//////抛出一个ArgumentNullException如果任何传递的表达式的值为null。//////要分析的lambda表达式。///lambdas必须是()=>variableName的形式。///publicstaticvoidCheckForNullArg(paramsExpression>[]exprs){foreach(varexprinexprs)if(expr.Compile()()==null)thrownewArgumentNullException(expr.GetName());}}...可以这样使用://usage:ExHelper.CheckForNullArg(()=>someParam,()=>someOtherParam);这将样板文件减少到一行,无需第三方工具ExpressionReader和异常生成方法可以处理在调用者中编译的form()=>variableName任何lambda,这意味着它至少适用于局部变量、参数、实例字段和实例属性.我没有检查它是否适用于静力学。公共类TestClass{publicTestClass(){this.ThrowIfNull(t=>t.Str,t=>t.Test);//或//this.ThrowIfNull(t=>tX)//.ThrowIfNull(t=>t.Test);}字符串Str="";publicTestClassTest{set;get;}}publicstaticclassSOExtension{publicstaticTThrowIfNull(thisTtarget,paramsExpression>[]exprs){foreach(vareinexprs){varexp=e.BodyasMemberExpression;if(exp==null){thrownewArgumentException("参数'expr'的格式必须为x=>x.variableName");}varname=exp.Member.姓名;if(e.Compile()(target)==null)thrownewArgumentNullException(name,"Parameter["+name+"]cannotbenull");}返回目标;如果您不反对第三方实用程序,PostSharp提供了一种巧妙的方式来注入此类验证。这篇博文为您的问题提供了解决方案。更新:请参阅PostSharp3中的新验证参数功能扩展方法怎么样?publicstaticvoidThrowExceptionIfNull(thisobjectargument,stringargumentName){if(argument==null)thrownewArgumentNullException(argumentName);然后你的代码至少读起来更流畅一点:someParam.ThrowExceptionIfNull("someParam");否则,我会同意其他人拆分功能或使用AOP(即PostSharp)已经有很多有效的解决方案,但我的看法是:使用System.Diagnostics;使用System.Reflection;publicSomeConstructor(int?par1,int?par2,stringpar3){CheckThrowNull(par1,par2,par3);//其余构造函数代码...}///值必须按顺序给出publicstaticvoidCheckThrowNull(paramsobject[]values){StackTracestackTrace=newStackTrace();ParameterInfo[]parameters=stackTrace.GetFrame(1).GetMethod().GetParameters();//获取调用方法的参数(或构造函数)if(parameters.Length!=values.Length){thrownewArgumentException("Incorrectnumberofvaluespassedin");}for(inti=0;i总体思路是创建两个并行数组,一个是ParameterInfo类型,另一个包含参数值。后者必须传入,因为参数值不容易(我认为不可能)通过反射得到。为了给予应有的信任,我在这里找到了如何获取调用方法:http://www.csharp-examples.net/reflection-calling-method-name/就个人而言,我不喜欢使用System.Diagnosics,除了调试,所以我稍微修改一下,调用代码是:CheckThrowNull(MethodBase.GetCurrentMethod(),par1,par2,par3);方法是CheckThrowNull(MethodBasemethod,paramsobject[]values){ParameterInfo[]parameters=method.GetParameters();//其余代码相同}下端有点不可扩展,并且不能轻易检查只有一些参数为空。试试这个:一行。账户=账户??抛出新的ArgumentNullException(nameof(accounts));此外,使用nameof(),如果变量被重命名,您不必查找所有“变量”,让nameof()来做。嗯,样板是很难避免的。您可以改用BertrandMeyers的Eiffel编程语言和EiffelStudio而不是C#和VisualStudio,并开始练习DesignbyContract?。今天,Eiffel完全符合CLR。我编写了基准测试应用程序,提取了参数名称的多种变体(通过匿名类+反射/MemberExpression/Func/等)Github基准测试源链接:https://github.com/iXab3r/NullCheckCompetition我得到的结果显示,最快方法是使用匿名类。.NET40/X64失败(即参数为null并且名称提取方法执行)成功(即参数不为null)实际上,可以从lambda表达式中检索参数名称,而无需通过Expression类型。下面是它是如何完成的:staticvoidSampleMethod(stringarg1){ThrowIfNull(()=>arg1);//在这里继续其他正常的事情...}publicstaticvoidThrowIfNull(Funclambda)whereT:class{if(lambda()==null){thrownewArgumentNullException(lambda.Target.GetType().GetFields()[0].姓名);我认为上面的大部分都很好,但它们都没有真正改善你已经拥有的东西,所以我只想去KIS,KeepItSimple,这就是你开始的地方。它干净、可读性极强且速度很快。上面唯一有点长的是C#学习教程:ArgumentNullException——如何化简?如果分享的所有内容对您有用,需要了解更多C#学习教程,希望您多多关注---本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
