如果一个参数为null,最佳做法是什么?

在validation方法的输入时,我曾经检查参数是否为null,如果是,我抛出一个ArgumentNullException。 我为列表中的每个参数执行此操作,因此我最终得到如下代码:

public User CreateUser(string userName, string password, string Email, string emailAlerts, string channelDescription) { if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException("Username can't be null"); if (string.IsNullOrEmpty(Email)) throw new ArgumentNullException("Email can't be null"); //etc, etc, etc } 

这个可以吗? 我为什么要这样做? 如果我只是将所有检查分组并返回空值而不是抛出exception,那会没关系吗? 解决这种情况的最佳做法是什么?

PS:我想改变这个,因为使用长方法,这样做非常繁琐。
想法?

用这样的东西制作一个ArgChecker类

  ArgChecker.ThrowOnStringNullOrEmpty(userName, "Username"); 

其中ThrowOnStringNullOrEmpty是

  public static void ThrowOnStringNullOrEmpty(string arg, string name) { if (string.IsNullOrEmpty(arg)) throw new ArgumentNullException(name + " can't be null"); } 

您还可以尝试使用params arg处理参数列表,例如:

  public static void ThrowOnAnyStringNullOrEmpty(params string[] argAndNames) { for (int i = 0; i < argAndName.Length; i+=2) { ThrowOnStringNullOrEmpty(argAndNames[i], argAndNames[i+1]); } } 

并像这样打电话

  ArgChecker.ThrowOnAnyStringNullOrEmpty(userName, "Username", Email, "email"); 

我使用的方法和我可能从NHibernate源代码中获取的方法是创建一个静态类Guard ,使用方法如下:

 public void Foo(object arg1, string arg2, int arg3) { Guard.ArgumentNotNull(arg1, "arg1"); Guard.ArgumentNotNullOrEmpty(arg2, "arg2"); Guard.ArgumentGreaterThan(arg3, "arg3", 0); //etc. } public static class Guard { public static void ArgumentNotNull(object argument, string parameterName) { if (parameterName == null) throw new ArgumentNullException("parameterName"); if (argument == null) throw new ArgumentNullException(parameterName); } //etc. } 

这在方法开始时减少了很多糠and,并且表现良好。

您应该考虑方法,需要做什么以及使用哪些数据。 如果空值表示实际故障条件,请使用exception。 如果可以接受空值,则接受它们。

从设计合同中考虑原则,特别是你的function的先决条件是什么,并规范一种强制执行的方式(Matt和Lou都在他们的答案中提出建议,所以我不需要详细说明)。

另一个需要考虑的重要事项是方法签名的大小。 如果你的方法有很多参数,这可能意味着你有很糟糕的抽象。 如果在集合对象中将参数组合在一起并将这些对象用作参数,则可以减少必须进行的参数检查的数量。 您可以将参数检查移动到这些对象,而不必在使用它们的每个函数中检查它们。

因此,不是将十个相关参数传递给每个函数,而是找出每个函数中使用的少数参数并将它们打包在一个对象中,并在该对象中包含validation参数的方法。 如果需要更新关于一个参数的规则,这具有易于改变的附加优点。

对于我们中的C#3.0开发人员来说,封装此null检查的一种很好的方法是在扩展方法中。

 public void Foo(string arg1, int? arg2) { arg1.ThrowOnNull(); arg2.ThrowOnNull(); } public static class extensions { public static void ThrowOnNull(this T argument) where T : class { if(argument == null) throw new ArgumentNullException(); } } 

如果你想要你可以总是重载它以获取参数名称。

对Lou的答案的一个小改进是使用哈希表,它意味着它检查对象以及字符串。 还可以更好地填充和处理方法:

 public static class ParameterChecker { public static void CheckForNull(Hashtable parameters) { foreach (DictionaryEntry param in parameters) { if (param.Value == null || string.IsNullOrEmpty(param.Value as string)) { throw new ArgumentNullException(param.Key.ToString()); } } } } 

就像你会喜欢的那样:

 public User CreateUser(string userName, string password, string Email, string emailAlerts, string channelDescription) { var parameters = new Hashtable(); parameters.Add("Username", userName); parameters.Add("Password", password); parameters.Add("EmailAlerts", emailAlerts); parameters.Add("ChannelDescription", channelDescription); ParameterChecker.CheckForNull(parameters); // etc etc } 

我会坚持你的原始方法,除了传递参数名称。 原因是,一旦你开始编写这些帮助程序,当每个人开始使用不同的约定来编写帮助程序时,这就成了一个问题。 当有人查看您的代码时,他们现在必须检查以确保在调试代码时正确编写了帮助程序。

分别检查每个参数,虽然你的手指因输入Grasshopper而感到厌倦:)你的粉丝会在遇到意外的ArgumentException时保佑你,并从调试运行中保存以确定哪个参数失败。

我给你的第一个建议是获得ReSharper。 它会告诉您何时存在可能的空值问题,并且当不需要检查它们时,单击鼠标将添加检查。 话说回来…

除非您从某些旧版源接收信息,否则通常不必检查空字符串和整数。

可以使用string.IsNullOrEmpty()检查字符串…

如果您仍然决定要检查每个参数,可以使用命令设计模式和reflection,但是您的代码将不必要地笨重,或者使用以下内容并为每个方法调用它:private myType myMethod(string param1,int param2,byte [] param3){CheckParameters(“myMethod”,{param1,param2,param3}); //其余代码……

在你的实用程序类中放这个:

 ///Validates method parameters ///... rest of documentation public void CheckParameters(string methodName, List parameterValues) { if ( string.IsNullOrEmpty(methodName) ) throw new ArgumentException("Fire the programmer! Missing method name", "methodName")); Type t = typeof(MyClass); MethodInfo method = t.GetMethod(methodName); if ( method == null ) throw new ArgumentException("Fire the programmer! Wrong method name", "methodName")); List params = method.GetParameters(); if ( params == null || params.Count != parameterValues.Count ) throw new ArgumentException("Fire the programmer! Wrong list of parameters. Should have " + params.Count + " parameters", "parameterValues")); for (int i = 0; i < params.Count; i++ ) { ParamInfo param = params[i]; if ( param.Type != typeof(parameterValues[i]) ) throw new ArgumentException("Fire the programmer! Wrong order of parameters. Error in param " + param.Name, "parameterValues")); if ( parameterValues[i] == null ) throw new ArgumentException(param.Name + " cannot be null"); } } // enjoy