Reputation: 28081
I knew the first half part of the magic. Assume I have:
public class Foo {}
public class static FooExt
{
public static void M(this Foo f) {}
}
When I invoke foo.M()
the compiler changes it to FooExt.M(foo)
.
But how about the inheritance? For example:
public class Bar : Foo {}
public class static BarExt
{
public static void M(this Bar b) {}
}
When I invoke bar.M()
will it call FooExt.M()
or BarExt.M()
? In fact I tested it and the answer is BarExt
, but why? What happens when I call wow.M()
if I have another Wow : Foo
but no WowExt.M()
?
Upvotes: 2
Views: 224
Reputation: 245429
When resolving extension methods, the most specific type match will be selected. In your first case, BarExt.M()
is the most specific (targets Bar
rather than Foo
).
In the second case, there is no Wow
extension so the most specific match would be FooExt.M()
.
Upvotes: 3
Reputation: 152556
I tested it and the answer is
BarExt
, but why?
Because the compiler will choose the extension method that "best fits" the call. Since there is a method that takes a Bar
directly, that one is chosen.
What happens when I call wow.M() if I have another Wow : Foo but no WowExt.M()?
Again, it will choose the extension that "best fits" the usage. Since there is no method that takes a Wow
, but one that does take it's parent class Foo
it will choose FooExt.M()
Remember that extension methods are really just syntactic sugar for static method calls, so the same rules apply to them as "normal" method resolution.
Upvotes: 5
Reputation: 169018
The compiler will look for the extension method whose arguments most closely match those at the invocation site. If you have a variable of type Bar
then the BarExt
extension would be used, since Bar
is more specific a type than Foo
, and therefore matches more closely than the alternative method that takes a Foo
instance. This really is not very different from how ambiguous method overloads are resolved.
It is worth noting that this code will call FooExt.M()
:
Foo bar = new Bar();
bar.M();
This is because extension methods are not virtual. Since the variable you are invoking the method on is type Foo
, the Bar
version of the extension method will not even be considered. Binding of extension methods happens entirely at compile time.
In the second case you indicated (invoking the extension method on a variable of type Wow
), the FooExt.M()
method would be used, since there is nothing that matches better.
Upvotes: 10