2

我知道魔法的前半部分。假设我有:

public class Foo {}
public class static FooExt
{
    public static void M(this Foo f) {}
}

当我调用foo.M()编译器将其更改为FooExt.M(foo).

但是继承呢?例如:

public class Bar : Foo {}
public class static BarExt
{
    public static void M(this Bar b) {} 
}

当我调用bar.M()时,它会调用FooExt.M()orBarExt.M()吗?事实上我测试了它,答案是BarExt,但为什么呢?wow.M()如果我有另一个Wow : Foo但没有,当我打电话时会发生什么WowExt.M()

4

3 回答 3

10

编译器将寻找其参数与调用站点的参数最接近的扩展方法。如果您有一个类型的变量,Bar那么BarExt将使用扩展,因为Bar它比 更具体,因此比采用实例Foo的替代方法更匹配。Foo这与如何解决模棱两可的方法重载并没有太大区别。

值得注意的是,这段代码将调用FooExt.M()

Foo bar = new Bar();
bar.M();

这是因为扩展方法不是虚拟的。由于您调用方法的变量是 type Foo,因此Bar甚至不会考虑扩展方法的版本。 扩展方法的绑定完全在编译时发生。

在您指出的第二种情况下(对 type 的变量调用扩展方法Wow),FooExt.M()将使用该方法,因为没有比这更好的方法了。

于 2013-01-21T22:41:40.180 回答
5

我测试了它,答案是BarExt,但是为什么呢?

因为编译器会选择“最适合”调用的扩展方法。由于有一种Bar直接采用 a 的方法,因此选择了该方法。

如果我有另一个 Wow : Foo 但没有 WowExt.M(),当我调用 wow.M() 会发生什么?

同样,它将选择“最适合”使用的扩展。由于没有采用 a 的方法Wow,但采用它的方法是它的父类Foo,它会选择FooExt.M()

请记住,扩展方法实际上只是静态方法调用的语法糖,因此相同的规则适用于它们作为“正常”方法解析。

于 2013-01-21T22:41:44.573 回答
3

解析扩展方法时,将选择最具体的类型匹配。在您的第一种情况下,BarExt.M()是最具体的(目标Bar而不是Foo)。

在第二种情况下,没有Wow扩展名,因此最具体的匹配是FooExt.M().

于 2013-01-21T22:42:31.427 回答