想象一下,我们定义了一个采用这种形式的扩展方法:
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
}
}
在这里,我们Baz
在Foo
类上公开了一个公共扩展方法(示例很简单)。现在,如果我们有以下用法:
Foo foo1 = null;
foo1.Bar(0); // throws NullReferenceException
Foo foo2 = null;
foo2.Baz(); // again throws NullReferenceException
因此,两种情况下的代码都会表现一致——无论调用成员方法还是扩展方法,我们都会抛出相同的 NullReferenceException()。这让我觉得情况有些不对劲。我的想法是:
NullReferenceExceptions
根据大多数准则,允许的代码很差。扩展方法就是这种不良做法的一个例子。为了遵守指南并像公共 API 一样公开防故障代码,必须进行一些空安全检查,如下所示:
public static void Baz(this Foo @this) { if (@this == null) { 抛出新的 ArgumentNullException("@this"); } @this.Bar(0); }
- 行为的一致性将允许开发人员轻松检测空引用情况,因为两种情况的行为相同。我的意思是,调用扩展方法对编码人员来说并不总是显而易见的,所以如果该行
foo2.Baz()
抛出 aNullReferenceException
很明显foo2
就是null
.
上述矛盾使我得出一些结论。第二点忽略了一个重要的问题——堆栈跟踪。在标准NullPointerException
情况下,堆栈跟踪直接导致foo1.Bar(0)
行。在扩展方法中,它将指向扩展方法中引发异常的行。因此,一致的行为仍然具有不一致的堆栈跟踪。
现在的问题是——关于零安全性,“最佳实践”如何应用于第三方将使用的扩展方法?我们是否应该通过始终在参数上添加参数防空验证来忽略一致性@this
?或者它是一个可以让我们绕过良好实践建议的极端案例?
编辑
我正在解决一个带有扩展的库将被暴露的情况。它不会使用 PostSharp 或其他类似技术等非内置/第 3 方解决方案。还需要与 .NET 3.5 完全兼容。