In a recent question of mine I learned that if there are more than one extension methods with constraints that match the given type, the most specific one will be chosen. This got me thinking - how does the compiler determine which one is "more specific"? And what will the outcome be?
Let's say I have the following classes:
public MyClass : IComparable, IDisposable
{
// Implementation of members
}
public static class MyExtensions
{
public static void DoSomething<T>(this T item)
where T : IComparable
{ /* whatever */ }
public static void DoSomething<T>(this T item)
where T : IDisposable
{ /* whatever else */ }
}
If I now use the extension method as
var instance = new MyClass();
instance.DoSomething();
which method will be used? Or will the compiler throw an error?
Note: I'm not saying this is good design, or even that I have a case where I need to do this. But the term "more specific" was loose enough to make me ponder this, and now I have to know! :P
Update: I guess I wasn't really as interested in what will happen in the above example, as in why. It came to my mind since I'd been doing stuff like
public static class CollectionExtensions
{
public static void DoSomething<T>(this T items) where T : IList { ... }
public static void DoSomething<T>(this T items) where T : IEnumerable { ... }
}
where the compiler knows to choose the first method for new List<Something>().DoSomething()
, since it is "closer" to the type passed. What I was interested in then, was "what does closer in this context mean? How will the compiler react if the constraints are from two different inheritance chains? Why?"
The extensions class won't compile, in this case - you can't overload methods based solely on generic constraints.
If you put the two extension methods into different classes, then the calling code wouldn't compile - it would be an ambiguous call, as neither method would be "better" than the other... in both cases the generic type argument would be inferred as MyClass
, so there'd just be two conversions from MyClass
to MyClass
, neither of which is better than the other.
This is basically just a special case of overloading, once you've found out that no instance methods are applicable. I wrote an article on overloading just recently which you may find useful - it doesn't call out this specific case, but it points to the relevant bits of the spec if you want to look in detail.
It will not compile at all and throw a compile time error saying call is ambiguish between the two methods.
Type 'MyExtensions' already defines a member called 'DoSomething' with the same parameter types.
Here's why compiler gives such error. Extension methods are just syntactic sugars and all they do is bring fluency and readabilty on any type.
Check this code..
var instance = new MyClass();
instance.DoSomething();
Compiler replaces this code as following.
var instance = new MyClass();
MyExtensions.DoSomething(instance);
//Compiler gets confused. Which one to call IComparable or IDisposable
In your case compiler gets confused since there are two matching signatures to the method-call and it gives you the said error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With