我注意到这段代码在我的构造函数中出现得很多:
if (someParam == null) throw new ArgumentNullException("someParam");
if (someOtherParam == null) throw new ArgumentNullException("someOtherParam");
...我有几个构造器,其中有几个东西被注入,并且必须都是非空的。有没有人能想出一种方法来简化这个过程?我唯一能想到的是:
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);
}
}但是,它的用法如下所示:
ExceptionHelper.CheckAndThrowArgNullEx(new [] {
new KeyValuePair<string, object>("someParam", someParam),
new KeyValuePair<string, object>("someOtherParam", someOtherParam),
... });..。这对简化代码并没有真正的帮助。Tuple.Create()而不是KVP无法工作,因为元组的GTP不是协变的(即使IEnumerable的GTP是协变的)。有什么想法吗?
发布于 2012-08-21 04:41:32
对于你们中的大多数人来说,你们的回答有助于我最终得出的解决方案,它包含了一些零碎的东西,但最终都是不同的。
我创建了两个静态方法,用于处理特定形式的lambda表达式(编辑-小更改;这些方法不能是泛型的,否则它们将要求所有表达式返回相同的类型。Func是好的,在GetName方法中有一个额外的条件来解开类型转换):
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());
}
}..。它可以这样使用:
//usage:
ExHelper.CheckForNullArg(()=>someParam, ()=>someOtherParam);这将样板文件减少到一行,而不需要第三方工具。ExpressionReader和异常生成方法都适用于在调用方中编译的()=>variableName形式的任何lambda,这意味着它至少适用于局部变量、参数、实例字段和实例属性。我还没有检查它在静态上是否有效。
发布于 2012-08-21 03:56:35
C# 7的更新
您可以将throw expression与null合并运算符一起使用。下面是该页面中一个示例:
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。这很好,因为你可以用返回值进行赋值:
public static T ThrowIfNull<T>(this T argument, string argumentName)
{
if (argument == null)
{
throw new ArgumentNullException(argumentName);
}
return argument;
}用法:
this.something = theArgument.ThrowIfNull("theArgument");
// or in C# 6
this.something = theArgument.ThrowIfNull(nameof(theArgument));(尽管有些人认为在空实例上调用扩展方法很奇怪)
如果你真的想一次检查多个参数,如果你像这样使用一个params签名,你的例子可能会更流畅:
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);
}
}
}它的用法是:
CheckAndThrowArgNullEx(arg1, "arg1", arg2, "arg2");
// or in C# 6
CheckAndThrowArgNullEx(arg1, nameof(arg1), arg2, nameof(arg2));再三考虑,正如KeithS在评论中提到的那样,将其实现为一组重载可能比像这样使用params object[]更好:
static void Check(object arg1, string arg1Name) { ... }
static void Check(object arg1, string arg1Name, object arg2, string arg2Name) { ... }
// and so on...发布于 2018-03-07 01:03:00
试试这个:一行。
accounts = accounts ?? throw new ArgumentNullException(nameof(accounts));此外,使用nameof(),如果变量被重命名,你将不必寻找所有的“变量”,让nameof()来做。
https://stackoverflow.com/questions/12043875
复制相似问题