大家都这样做:
public void Proc(object parameter)
{
if (parameter == null)
throw new ArgumentNullException("parameter");
// Main code.
}
乔恩斯基特曾经提到,他有时使用扩展做此项检查,所以你可以做:
parameter.ThrowIfNull("parameter");
所以我来的这个扩展的两种实现方式,我不知道哪一个是最好的。
第一:
internal static void ThrowIfNull<T>(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<T>(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
物体似乎荒谬的(虽然我知道这是完全有效的空方法调用对扩展方法)。
至于这是最好的,我会用也没有。 他们都有无限递归 。 我还懒得守着消息参数,使其可选择空。 第一个解决方案也将不支持Nullable<T>
类型为class
约束块它。
我们的Guard
班也有Contract.EndContractBlock()
后呼吁,当我们决定启用代码契约,因为它符合所要求的“如果-那么掷”结构。
这也是一个完美的候选人PostSharp方面 。
我会做这样既避免了硬编码参数名称。 明天它可以改变的,你有更多的工作,那么:
public static void ThrowIfNull<T>(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();
您可以缓存属性值,以进一步提高性能,属性名称不运行期间更改。
另外看到这个问题: 在运行时解析参数名称
关于使用什么表达式树(从Visual Studio的杂志 ):
using System;
using System.Linq.Expressions;
namespace Validation
{
public static class Validator
{
public static void ThrowIfNull(Expression<Func<object>> 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<Func<String>> 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);
}