Lai Yu-Hsuan
Lai Yu-Hsuan

Reputation: 28081

How do extension methods work with inheritance?

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

Answers (3)

Justin Niessner
Justin Niessner

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

D Stanley
D Stanley

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

cdhowie
cdhowie

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

Related Questions