扩展空检查的最佳方法是什么?

你这都是这样的:

public void Proc(object parameter) { if (parameter == null) throw new ArgumentNullException("parameter"); // Main code. } 

Jon Skeet曾经提到他有时会使用扩展来进行检查,所以你可以做到:

 parameter.ThrowIfNull("parameter"); 

所以我得到了这个扩展的两个实现,我不知道哪个是最好的。

第一:

 internal static void ThrowIfNull(this T o, string paramName) where T : class { if (o == null) throw new ArgumentNullException(paramName); } 

第二:

 internal static void ThrowIfNull(this object o, string paramName) { if (o == null) throw new ArgumentNullException(paramName); } 

你怎么看?

我使用internal static void ThrowIfNull(this T o, string paramName) where T : class 。 我不会使用internal static void ThrowIfNull(this object o, string paramName)因为它可能会进行装箱。

我倾向于坚持无处不在的Guard类:

 static class Guard { public static void AgainstNulls(object parameter, string name = null) { if (parameter == null) throw new ArgumentNullException(name ?? "guarded argument was null"); Contract.EndContractBlock(); // If you use Code Contracts. } } Guard.AgainstNulls(parameter, "parameter"); 

并且避开扩展object ,加上肉眼对null对象的方法调用似乎是荒谬的(尽管我知道对扩展方法进行空方法调用是完全有效的)。

至于哪个最好,我也不使用。 它们都有无限的递归 。 我也不打扰保护message参数,使其可选为null。 您的第一个解决方案也不支持Nullable类型,因为class约束会阻止它。

我们的Guard类也在它之后调用Contract.EndContractBlock() ,当我们决定启用Code Contracts时,因为它适合所需的“if-then-throw”结构。

这也是PostSharp方面的完美候选者。

我会这样做以避免硬编码参数名称。 明天它可以改变,然后你还有更多的工作:

 public static void ThrowIfNull(this T item) where T : class { if (item == null) return; var param = typeof(T).GetProperties()[0]; if (param.GetValue(item, null) == null) throw new ArgumentNullException(param.Name); } 

并称之为:

 public void Proc(object parameter) { new { parameter }.ThrowIfNull(); //you have to call it this way. // Main code. } 

性能影响微不足道(在我平庸的计算机上,它在25毫秒内运行了100000次),比通常看到的基于表达式的方法快得多

 ThrowIfNull(() => resource); 

一个这样的。 但是,如果你不能承受这么大的打击,肯定不要使用它。

您还可以为对象的属性扩展它。

 new { myClass.MyProperty1 }.ThrowIfNull(); 

您可以缓存属性值以进一步提高性能,因为属性名称在运行时不会更改。

另外请参阅此问题: 在运行时解析参数名称

如何使用Expression Trees(来自Visual Studio Magazine ):

 using System; using System.Linq.Expressions; namespace Validation { public static class Validator { public static void ThrowIfNull(Expression> expression) { var body = expression.Body as MemberExpression; if( body == null) { throw new ArgumentException( "expected property or field expression."); } var compiled = expression.Compile(); var value = compiled(); if( value == null) { throw new ArgumentNullException(body.Member.Name); } } public static void ThrowIfNullOrEmpty(Expression> expression) { var body = expression.Body as MemberExpression; if (body == null) { throw new ArgumentException( "expected property or field expression."); } var compiled = expression.Compile(); var value = compiled(); if (String.IsNullOrEmpty(value)) { throw new ArgumentException( "String is null or empty", body.Member.Name); } } } 

}

像这样使用:

 public void Proc(object parameter1, object parameter2, string string1) { Validator.ThrowIfNull(() => parameter1); Validator.ThrowIfNull(() => parameter2); Validator.ThrowIfNullOrEmpty(() => string1); // Main code. } 

第二个似乎更优雅的处理方式相同。 在这种情况下,您可以对每个托管对象设置限制。

 internal static void ThrowIfNull(this object o, string paramName) { if (o == null) throw new ArgumentNullException(paramName); }