扩展方法能在没有对象的情况下被调用吗?

6
以下代码为什么有效?
调用:
SomeObject sO = null;
bool test = sO.TestNull();

代码:

public static bool TestNull(this SomeObject sO)
{
    return sO == null;
}

这是允许工作的还是只是一个 bug?


11
这个 null.TestNull(); 不应该编译通过。 - Habib
我认为应该是sO.TestNull() - Sergey Berezovskiy
我认为你的意思是sO为空时,应该写成bool test = sO.TestNull()吧? - quetzalcoatl
这不是一个有效的代码,无法编译。 - Ravi
1
@dasblinkenlight 我想在问题被更正以便编译之前,已经有人给它点了踩。 - Matthew Watson
显示剩余5条评论
4个回答

13

这是可以运行的还是只是一个 bug?

你在编辑问题后将null.TestNull()改为s0.TestNull()后的代码是可以正常工作的。

扩展方法就是调用静态方法的一种语法糖,使其看起来像实例方法。因此以下调用是等效的:

s0.TestNull()

被转换为

ClassContainingExtensionMethod.TestNull(s0)

...就是这样了。不会自动执行任何空值检查。

这实际上可以非常有用-想象一下如果 string.IsNullOrEmpty 是一个扩展方法-那么你可以这样编写:

string.IsNullOrEmpty(myString)

if (string.IsNullOrEmpty(foo))

你可以写得更易读:

if (foo.IsNullOrEmpty())
然而需要注意的是,这种能力不应该被轻易使用 - 如果第一个参数为空值,大部分扩展方法应该抛出 ArgumentNullException 异常,并且那些不抛出异常的方法应该非常明确地说明。 (这样的方法中较少见到在名称中包含Null。)

1
@Moho:这是一个编译错误。你不能编译代码 null.TestNull()。(但你可以写成 ((SomeObject)null).TestNull() - Chris Sinclair
1
@Moho:真的吗? 你有尝试编译吗? 我试过了:“运算符'.'不能应用于类型为'<null>'的操作数”。请注意,这是在问题更改为使用s0.TestNull()之前。 - Jon Skeet
谢谢。我想知道是否可以将其用于特殊对象的扩展方法比较 => 如果s0 = null && 第二个也放入扩展方法的对象为null,则两者具有相等的值,因此应返回true。 - Offler
@Offler:我没有完全理解,但希望答案仍然有用——这样做基本上是可以的。 - Jon Skeet
1
@Moho:这里的重点是“null字面量”。也就是说,null.Method(..)的精确语法是不允许的。如果你以不同的方式编写它,即使是((object)null).Method(),它也不是相同的,而且是正确的! - quetzalcoatl
显示剩余2条评论

6
假设您的意思是
bool test = sO.TestNull();

那么答案就是静态函数不需要对象实例。此外,调用扩展函数只是调用带参数的函数的语法糖。
编辑:
我建议也阅读Jon Skeet的回答

4
代码应该是bool test = sO.TestNull();。是的,这个代码应该可以工作。
您正在使用函数扩展一个对象,无论对象是否为null或包含值,都不重要。这本质上与编写SomeStaticClass.TestNull(sO);相同。

2
正如Jon和其他人已经指出的那样,这是标准行为。它可以用于:
  • 触发事件并在此之前检查null值的扩展方法
  • 提供可能为空链的扩展方法,其中链中的每个部分都可能为空。
很久以前,我曾经想知道向空引用发送消息是否可行,但时间证明这是非常实用和有用的,特别是考虑到其他语言中根本不存在空引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接