在验证方法的输入时,我常常检查参数是否为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
}
这样好吗?我为什么要这样做?如果我只是将所有检查分组并返回空值而不是抛出异常,那会没关系吗?解决这种情况的最佳做法是什么?
PS:我想改变它,因为使用长方法,这样做非常繁琐。
想法?
答案 0 :(得分:17)
使用类似的东西制作一个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");
答案 1 :(得分:17)
我使用的方法和我可能从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.
}
这在方法开始时减少了很多糠,并且表现良好。
答案 2 :(得分:9)
您应该考虑方法,需要做什么以及使用哪些数据。如果空值表示实际故障条件,请使用异常。如果可以接受空值,则接受它们。
考虑来自design by contract的原则,特别是你的功能的先决条件是什么,并规范一种强制执行它们的方法(Matt和Lou都在他们的答案中提出建议,所以我不需要详细说明)。
要考虑的另一个重要事项是方法签名的大小。如果你的方法有很多参数,这可能意味着你有很糟糕的抽象。如果在集合对象中将参数组合在一起并将这些对象用作参数,则可以减少必须进行的参数检查的数量。您可以将参数检查移动到这些对象,而不必在使用它们的每个函数中检查它们。
因此,不是将十个相关参数传递给每个函数,而是找出每个函数中使用的少数参数并将它们打包在一个对象中,并在该对象中包含验证参数的方法。如果需要更新有关一个参数的规则,这具有易于更改的附加优点。
答案 3 :(得分:5)
对于我们中的C#3.0开发人员来说,封装此null检查的一种很好的方法是在扩展方法中。
public void Foo(string arg1, int? arg2)
{
arg1.ThrowOnNull();
arg2.ThrowOnNull();
}
public static class extensions
{
public static void ThrowOnNull<T>(this T argument) where T : class
{
if(argument == null) throw new ArgumentNullException();
}
}
如果你想要,你总是可以重载它以获取参数名称。
答案 4 :(得分:3)
对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
}
答案 5 :(得分:2)
除了传递参数名称外,我会坚持使用您的原始方法。原因是,一旦你开始编写这些帮助程序,当每个人开始使用不同的约定来编写帮助程序时,它就成了一个问题。当有人查看您的代码时,他们现在必须检查以确保在调试代码时正确编写了帮助程序。
分别检查每个参数,尽管你的手指因输入Grasshopper而感到厌倦:)你的粉丝会在遇到意外的ArgumentException时保佑你,并从调试运行中保存以确定哪个参数失败。
答案 6 :(得分:0)
使用带有多个 AggregateException
实例列表的 ArgumentNullException
(用于包含多个异常)。别忘了还利用 parameterName
的 ArgumentNullException
参数,它与 nameof()
配合得很好:
var exceptions = new List<Exceptions>();
if (firstArgument == null)
exceptions.Add(new ArgumentNullException(nameof(firstArgument), "Some optional message"));
if (secondArgument == null)
exceptions.Add(new ArgumentNullException(nameof(secondArgument), "Another optional message"));
if (exceptions.Count > 0)
throw new AggregateException(exceptions);
答案 7 :(得分:-1)
我给你的第一个建议是获得ReSharper。它会告诉您何时存在可能的空值问题,并且当不需要检查它们时,单击鼠标将添加检查。说完了......
除非您从某些旧版源接收信息,否则通常不必检查空字符串和整数。
可以使用string.IsNullOrEmpty()...
检查字符串如果您仍然决定要检查每个参数,可以使用命令设计模式和反射,但是您的代码将不必要地笨重,或者使用以下内容并为每个方法调用它: private myType myMethod(string param1,int param2,byte [] param3) { CheckParameters(“myMethod”,{param1,param2,param3}); //代码的其余部分......
在您的实用程序类中输入:
///<summary>Validates method parameters</summary>
///... rest of documentation
public void CheckParameters(string methodName, List<Object> 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<ParameterInfo> 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