我知道魔术的前半部分。假设我有:
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()
还是BarExt.M()
?事实上我测试了它,答案是BarExt
,但为什么呢?如果我有另一个wow.M()
但没有Wow : Foo
,当我致电WowExt.M()
时会发生什么?
答案 0 :(得分:10)
编译器将查找参数与调用站点上的最匹配的扩展方法。如果您有Bar
类型的变量,则会使用BarExt
扩展名,因为Bar
的类型比Foo
更具体,因此比其他选项更匹配采用Foo
实例的方法。这与模糊方法重载的解决方法确实没有什么不同。
值得注意的是,此代码将调用FooExt.M()
:
Foo bar = new Bar();
bar.M();
这是因为扩展方法不是虚拟的。由于您调用方法的变量是Foo
类型,因此甚至不会考虑扩展方法的Bar
版本。 扩展方法的绑定完全在编译时发生。
在您指出的第二种情况下(对Wow
类型的变量调用扩展方法),将使用FooExt.M()
方法,因为没有更好的匹配。
答案 1 :(得分:5)
我测试了它,答案是
BarExt
,但为什么?
因为编译器会选择“最适合”调用的扩展方法。由于有一种方法直接采用Bar
,因此选择了一种方法。
当我打电话给wow.M()时会发生什么?如果我有另一个Wow:Foo但没有WowExt.M()?
同样,它会选择“最适合”使用的扩展名。由于没有方法需要Wow
,但是它确实采用了它的父类Foo
,因此会选择FooExt.M()
请记住,扩展方法实际上只是静态方法调用的语法糖,因此相同的规则适用于它们作为“正常”方法解析。
答案 2 :(得分:3)
解析扩展方法时,将选择最具体的类型匹配。在第一种情况下,BarExt.M()
是最具体的(Bar
而不是Foo
)。
在第二种情况下,没有Wow
扩展名,因此最具体的匹配项为FooExt.M()
。