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)
这里我们Baz在Foo类上公开一个公共扩展方法(这个例子很简单).现在,如果我们有以下用法:
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完全兼容.
这取决于您如何查看扩展方法.鉴于它们仅仅是常规静态方法的语法糖,我会说它们应该遵循静态方法的指导原则 - 检查包括参数在内的所有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用于这些方法.
当我的组织内遇到这样的问题时,我默认采用惯例。
任何对此有意见的人都知道他们在说什么。这仅取决于他们是从实例还是静态方面查看扩展方法。
我之前使用过 WWLD(会LINQ做什么?),因为它是一个通用库,使用大多数 .NET 开发人员习惯的扩展方法。
示例代码:
IEnumerable<int> test = null;
test.Where(t => t > 0); // throws an ArgumentNullException
Run Code Online (Sandbox Code Playgroud)
因此,无论我的意见如何,我都会使用ArgumentNullException其他 .NET 开发人员所习惯的方式。
| 归档时间: |
|
| 查看次数: |
1754 次 |
| 最近记录: |