是否应该总是在.NET中编写null-proof扩展方法?

Iva*_*vov 4 .net c# extension-methods

想象一下,我们已经定义了一个采用这种形式的扩展方法:

public class Foo
{
    public void Bar(int arg) { ... }
}

public static class FooExtensions
{
     public static void Baz(this Foo @this)
     {
         @this.Bar(0);// not null-proof
     }
}
Run Code Online (Sandbox Code Playgroud)

这里我们BazFoo类上公开一个公共扩展方法(这个例子很简单).现在,如果我们有以下用法:

Foo foo1 = null;
foo1.Bar(0); // throws NullReferenceException
Run Code Online (Sandbox Code Playgroud)
Foo foo2 = null;
foo2.Baz(); // again throws NullReferenceException
Run Code Online (Sandbox Code Playgroud)

因此,两种情况下的代码都将表现一致 - 无论调用成员方法还是扩展方法,我们都会得到相同的NullReferenceException()抛出.这让我觉得情况有些不妥.我的想法是:

  • NullReferenceExceptions根据大多数指南,允许的代码很差.扩展方法就是这种不良做法的一个例子.为了遵守指南并公开应该是公共API 的防故障代码,必须进行如下的一些空安全检查:
    public static void Baz(this Foo @this)
    {
        if (@this == null) 
        {
            throw new ArgumentNullException("@this");
        }
        @this.Bar(0);
    }
  • 行为的一致性将允许开发人员轻松检测空引用情况,因为两种情况都表现相同.我的意思是,对编码人员来说,调用扩展方法并不总是显而易见的,所以如果该行foo2.Baz()抛出一个NullReferenceException很明显foo2就是这样null.

上述矛盾引出了一些结论.第二点错过了一个重要的问题 - 堆栈跟踪.在标准NullPointerException情况下,堆栈跟踪foo1.Bar(0)直接通向线路.在扩展方法中,它将指向抛出异常的扩展方法中的行.因此,一致行为仍然存在不一致的堆栈跟踪.

现在的问题 - 关于零安全性,"最佳实践"如何适用于第三方将要使用的扩展方法?我们是否应该通过在@this参数上添加参数null-proof validation来忽略一致性?或者它是一个可以让我们绕过良好实践建议的角落案例?

编辑

我正在解决一个带有扩展的库将被暴露的情况.它不会使用非内置/第三方解决方案,如PostSharp或其他类似技术.还需要与.NET 3.5完全兼容.

Ale*_*ill 8

这取决于您如何查看扩展方法.鉴于它们仅仅是常规静态方法的语法糖,我会说它们应该遵循静态方法的指导原则 - 检查包括参数在内的所有this参数.

如果你有专门处理的扩展,这是特别适用的null- 我知道它不是大多数人的首选扩展使用,但我喜欢以下方法:

public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source)
{
    return source ?? Enumerable.Empty<T>();
}

public static void DisposeIfNotNull(this IDisposable source)
{
    if (source != null)
        source.Dispose();
}
Run Code Online (Sandbox Code Playgroud)

显然,必须允许参数null用于这些方法.

  • 而且流行的`public static bool IsNullOrWhitespace(this string text){return string.IsNullOrWhiteSpace(text); }` (2认同)
  • 我编写了许多旨在接受空参数的扩展方法。通常,它们是目标类上现有方法的镜像,但如果调用该方法的对象为空,我想避免错误。在这些情况下,我通常将我的扩展方法命名为:“...NullSafe(...)”,这样当我或其他人使用它们时,我们知道它们将返回“null”或默认值(如果它们所在的对象)被称为 null。 (2认同)

Nic*_*man 8

当我的组织内遇到这样的问题时,我默认采用惯例。

任何对此有意见的人都知道他们在说什么。这仅取决于他们是从实例还是静态方面查看扩展方法。

我之前使用过 WWLD(会LINQ做什么?),因为它是一个通用库,使用大多数 .NET 开发人员习惯的扩展方法。

示例代码:

IEnumerable<int> test = null;
test.Where(t => t > 0); // throws an ArgumentNullException
Run Code Online (Sandbox Code Playgroud)

因此,无论我的意见如何,我都会使用ArgumentNullException其他 .NET 开发人员所习惯的方式。

  • WWLD 对我来说是新的,从现在开始我会用它作为我生活的指导:) (3认同)