什么是延长空检查的最佳方式?(What is the best way to extend null

2019-07-30 11:00发布

大家都这样做:

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);
}

你怎么看?

Answer 1:

我最好使用internal static void ThrowIfNull<T>(this T o, string paramName) where T : class 。 我不会用internal static void ThrowIfNull(this object o, string paramName)因为它可能会做拳击。



Answer 2:

我倾向于坚持无所不在的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方面 。



Answer 3:

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

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();

您可以缓存属性值,以进一步提高性能,属性名称不运行期间更改。

另外看到这个问题: 在运行时解析参数名称



Answer 4:

关于使用什么表达式树(从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.
}


Answer 5:

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

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


文章来源: What is the best way to extend null check?