Generic extension methods in C#: what will happen in this edge case? - c#

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.
EDIT
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.

Generic constraints are not considered as part of method signature. These two methods are considered by compiler as ones with the same signature. So you will get compile error saying that method DoSomething is already defined.
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 */ }

Consider the following example:
class MyClass {}
static class MyClassExtensions
{
public static void DoSomething<T>(this T item, List<string> someList)
{
Console.WriteLine("Method with List in signature is called.");
}
public static void DoSomething<T>(this T item, IEnumerable<string> someEnumerable)
{
Console.WriteLine("Method with IEnumerable in signature is called.");
}
}
In this example, when testing with the following:
var myClass = new MyClass();
myClass.DoSomething(new List<string>());
The first method in the extensions class is called. In short, this means that the compiler determines the signature that is nearer the arguments passed, and employs that.

Related

generic methods: how to force using the most specialized method available

I defined a generic method Use<T> in an interface IInterface. I tried to make an implementation of that interface where the concrete implementation of the Use<T> method depends on the actual type T, and I want to always call the most specialized method. But it does not work:
interface IInterface { void Use<T>(T other) where T : IInterface; }
interface IChildInterface : IInterface { }
class ImplementsIInterface : IInterface
{
public void Use<T>(T other) where T : IInterface
{
Debug.WriteLine("ImplementsInterface.Use(IInterface)");
}
}
class ImplementsChildInterface : IChildInterface
{
public void Use<T>(IChildInterface other) where T : IInterface
{ // idea: if other is IChildInterface, use this method
Debug.WriteLine("ImplementsChildInterface.Use(IChildInterface)");
}
public void Use<T>(T other) where T : IInterface
{ // idea: if above method is not applicable, use this method
Debug.WriteLine("ImplementsChildInterface.Use(IInterface)");
}
}
Here is my main method:
public static void Main()
{
IChildInterface childinterf = new ImplementsChildInterface();
childinterf.Use(new ImplementsChildInterface()); // outputs "ImplementsChildInterface.Use(IInterface)"
// but should output "ImplementsChildInterface.Use(IChildInterface)"
childinterf.Use(new ImplementsIInterface()); // outputs "ImplementsChildInterface.Use(IInterface)"
}
The method that takes an IChildInterface argument is never called, although it should.
Is there a way to make this work? Or is my approach fundamentally wrong?
Note that it is a necessity that IInterface only has one method definition. I might enlarge the interface hierarchy at any time (and thus increase the number of implementations I could provide in an implementing class), but this should not lead to needing to add more method definitions in IInterface. Otherwise, the whole point of using interfaces (i.e. to be flexible) would be missed.
The answers I got so far all involve the need to cast. This is also something I don't want to do, since it makes the whole setup useless. Let me explain the broader picture of what I try to achieve:
Let's imagine we created some instance of an IInterface (like so: IInterface foo = new ImplementsChildInterface();). It will behave in a certain way, but it will always behave in the same way - no matter if we see it as an IInterface, an IChildInterface or an ImplementsChildInterface. Because, if we call some method on it, the compiler (or runtime? i don't know) will check what type it REALLY is and run the method defined in that type.
Now imagine we have two instances i1 and i2 of IInterface. They again are, under the hood, concrete implementations of IInterface, so they have a concrete behaviour, no matter through which glasses we seem them.
So when I run i1.Use(i2), the compiler (or runtime?) should be able to find out what i1 and i2 REALLY are, and run the corresponding method. Like so:
Which type does i1 have? ImplementsChildInterface, ok, then I'll look at the methods there.
Which type does i2 have? ImplementsIInterface, ok, then let's see if there exists a method Use(ImplementsIInterface ...). There is none, but maybe there is a fallback? ImplementsIInterface is a IInterface, so let's see if there exists a method Use(IInterface ...). Yes, it exists, so let's call it!
Neither IInterface nor IChildInterface have a member Use<T>(IChildInterface other) defined, but only Use<T>(T other).
Your class ImplementsChildInterface on the other side has a method Use<T>(IChildInterface other). As you declaring childInterf as a reference of type IChildInterface you can´t access that member, but unly those defined in the interface. So you should cast to the actual class in order to access the method accepting an instance of IChildInterface. But even then the generic implementation is used. So you should also cast your parameter to IchildInterface:
ImplementsChildInterfacechildinterf = new ImplementsChildInterface();
childinterf.Use(((IChildInterface)new ImplementsChildInterface());
childinterf.Use(new ImplementsIInterface());
Furthermore as you don´t use the generic type-parameter within your more specialized method, you can also omit it:
class ImplementsChildInterface : IChildInterface
{
public void Use(IChildInterface other)
{ // idea: if other is IChildInterface, use this method
Debug.WriteLine("ImplementsChildInterface.Use(IChildInterface)");
}
public void Use<T>(T other) where T : IInterface
{ // idea: if above method is not applicable, use this method
Debug.WriteLine("ImplementsChildInterface.Use(IInterface)");
}
}
Alternativly you may also add a method into your IChildInterface:
void Use<T>(IChildInterface other) where T : IChildInterface;
Now you can use
IChildInterface childinterf = new ImplementsChildInterface();
childinterf.Use<IChildInterface>(new ImplementsChildInterface()); // outputs "ImplementsChildInterface.Use(IInterface)"
which will print the desired output.

Two-step method resolution with inheritance and generic constraints

I've encountered something quite surprising when using generic constraints with inheritance. I have an overloaded methods Foo that differ with parameter - either base or derived class instance. In both cases it's generally just passing the instance to the second pair of overloaded methods - Bar.
When I call Foo with base class instance, Bar overload for the base class is called. When I call Foo with derived class instance, Bar overload for the derived class is called. This is clear and expected.
But when I tried to merge Foo methods into single one GenericFoo that use generics and constraints, methods are resolved differently - T is resolved correctly, but only base-class overload of Bar is called.
public class Animal { }
public class Cat : Animal { }
public class AnimalProcessor
{
public static void Foo(Animal obj)
{
Console.WriteLine("Foo(Animal)");
Bar(obj);
}
public static void Foo(Cat obj)
{
Console.WriteLine("Foo(Cat)");
Bar(obj);
}
// new generic method to replace the two above
public static void GenericFoo<T>(T obj)
where T : Animal
{
Console.WriteLine("Foo(generic)");
Bar(obj);
}
public static void Bar(Animal obj)
{
Console.WriteLine("Bar(Animal)");
}
public static void Bar(Cat obj)
{
Console.WriteLine("Bar(Cat)");
}
}
Testing code - two first cases for non-generic old methods, two last for new generic method.
Console.WriteLine("Animal()");
AnimalProcessor.Foo(new Animal());
Console.WriteLine();
Console.WriteLine("Cat()");
AnimalProcessor.Foo(new Cat());
Console.WriteLine();
Console.WriteLine("Animal()");
AnimalProcessor.GenericFoo(new Animal());
Console.WriteLine();
Console.WriteLine("Cat()");
AnimalProcessor.GenericFoo(new Cat());
Console.ReadLine();
And the result - note the difference in type resolved in Bar:
Animal()
Foo(Animal)
Bar(Animal)
Cat()
Foo(Cat)
Bar(Cat)
Animal()
Foo(generic)
Bar(Animal)
Cat()
Foo(generic)
Bar(Animal)
It looks like the compiler binds all calls from GenericFoo to the least specific overload, even if all more specific-typed calls are known at compile time. Why is that, what is the reason for such behaviour? Which part of specs defines this?
Per OP's request, comment re-posted as answer:
Generics are not templates. Generic methods are compiled once and their behavior is for the 'most generic' case (in this case, Animal.) This is different from C++ style templating, where the template is compiled separately for each specialization by type.
The generic C# method is compiled into a generic IL method. And in IL, you have to explicitly specify which overload you are calling. So there is no simple way how the compiler could have done this. (There is complicated way: run a mini-compiler that chooses the overload at this point dynamically, which is what dynamic does.)
If you want this behavior, one option would be to make Bar() a virtual method on Animal. Another option would be using dynamic.

Invoking C# base class extension methods from inside derived class?

This is a contrived example:
public static class MyExtensions
{
public static void MyMethod( this MyInterface obj, string txt )
{
}
}
interface MyInterface {}
public MyDerived : MyInterface
{
void DoStuff()
{
MyMethod( "test" ); // fails; compiler can't find MyMethod?
}
}
In my example above, I'm trying to call an extension method assigned to an interface from my derived class. The compiler fails here and says that MyMethod does not exist in the current context. I have all the appropriate using statements in my CS file, so I'm not sure what is going on.
Try invoking it like this:
this.MyMethod("test");
Here is alternate solution (preferred by me):
(this as MyInterface).MyMethod("test");
Why? - because the solution provided previously will not work in cases when extension method calls class's "new" method (property is a method too). In such cases you may intend to call an extension method on the type declared by the base class/interface, which might behave differently from the derived class/interface.
Also, this solution will work for both "new" and "override" methods, because virtual "override" will anyway invoke derived version, which would be also intended.
EDIT: this may be irrelevant if you don't really want to pass "base" to the extension method and instead allow it take "this". However, you must consider behavioral differences.
Also, interesting to note as an answer to the comment by Darin Dimitrov: extension methods don't require instance to run them, because they are static methods. You can invoke an extension method as static by passing parameters to it. However, "base" is not a valid parameter value for parameter marked with "this" in the extension method declaration, which (if I were MS), would allow to simplify general usage of extension methods.
Try calling it this way instead:
this.MyMethod("test");
Change the call to
this.MyMethod("test")
This code compiles:
public static class MyExtensions
{
public static void MyMethod( this MyInterface obj, string txt )
{
}
}
public interface MyInterface {}
public class MyDerived : MyInterface
{
void DoStuff()
{
this.MyMethod( "test" ); // works now
}
}

Call method with covariant generic type specified in supplied parameter

The out keyword below is (as I didn't know, but for reasons that may be obvious to you) not allowed:
public static class DataExtensions {
public static void ReplaceAll<T>(this EntityCollection<T> collectionToReplace, IEnumerable<T> collectionToAdd) where T : EntityObject {
RemoveEach(collectionToReplace);
foreach (T item in collectionToAdd) collectionToReplace.Add(item);
}
public static void RemoveEach(this EntityCollection<out EntityObject> collectionToEmpty) {
if (!collectionToEmpty.IsLoaded) collectionToEmpty.Load();
while (collectionToEmpty.Any()) collectionToEmpty.Remove(collectionToEmpty.First());
}
}
and without it RemoveEach(collectionToReplace); has a parameter mismatch:
Argument 1: cannot convert from 'System.Data.Objects.DataClasses.EntityCollection<T>' to 'System.Data.Objects.DataClasses.EntityCollection<System.Data.Objects.DataClasses.EntityObject>'
The same, when calling with a specific (non-generic) derived type. Do I have to do use the following signature?
public static void RemoveEach<T>(this EntityCollection<T> collectionToEmpty) where T : EntityObject {
If so, intellisense or the compiler should warn me about using an abstract class as the generic type-specifier in this method, because I've just created an un-callable method, no? And if you don't mind, would you please point out why this is so (e.g. a scenario where type-safety would be broken or confusion would result if it were allowed).
Thank you, Shannon
You should just be able to use:
public static void RemoveEach<T>(this EntityCollection<T> collectionToEmpty)
where T : class
{
if (!collectionToEmpty.IsLoaded) collectionToEmpty.Load();
while (collectionToEmpty.Any()) collectionToEmpty.Remove(collectionToEmpty.First());
}
That's the only constraint that EntityCollection<T> requires, and you're not using anything within the method body which needs EntityObject.
By the way, is what you're doing here very different to calling collectionToEmpty.Clear()? I haven't used EF for a while, so it's not entirely obvious...

C# generic factory method

Perhaps this is a simple newbie C# question, but so be it---it will be a fresh break from my other questions, which are so difficult that no one knows the answer to them. :)
Let's say I have a generic type in C#:
Thing<T>
And let's say I want to make a thing using a static factory method. In Java, this is no problem:
public static <T> Thing<T> createThing()
{
return flag ? new Thing<Integer>(5) : new Thing<String>("hello");
}
How do I do this in C#? Thanks.
If you want to return an instance of a templated class using one of many different template arguments, one way to do it is with an abstract base (or an interface):
abstract class UntypedThing { }
class Thing<T> : UntypedThing
{
public Thing(T t) { }
}
class Foo
{
public static UntypedThing createThing(bool flag)
{
if (flag)
return new Thing<int>(5);
else return new Thing<String>("hello");
}
}
The UntypedThing class would contain as much code as possible that does not rely on the template type. The Thing class would ideally only contain code that relies on the template type. The factory class Foo always returns the former.
You can in theory use reflection to build up the correct generic type, but it will be pretty useless to you as at some point you will need to upcast it to a less specific type.
public class ThingFactory {
public object Create(bool flag) {
Type outputType = null;
if(flag) {
outputType = typeof(string);
} else {
outputType = typeof(int);
}
return Activator.CreateInstance(typeof(Thing<>).MakeGenericType(outputType));
}
}
As you can see, the value of doing this is about zero as you will need to cast the return type to the type you want, meaning that the logic to determine it needs to live outside the Create method.
I would use Reinderien's method and have a non-generic base. This is the most sane and idiomatic approach.
Oh, the trouble I get myself in when I simply try to do something simple.
It turns out that C# 4 allows this sort of covariance---sort of. First, I have to make Thing an interface and specify the "out" generic parameter:
public interface Thing<out T> {...}
But if I do certain things, C# won't let me use covariance. For example, if I try to return T from the interface:
public interface Thing<out T>
{
public T GetT();
Even if I manage to get covariance with Thing, what do I do with it?
Thing<object> thing=createThing();
The compiler tells me that the type cannot be inferred from usage.
Let's say I say screw the whole T thing and make the factory method return Thing of type object:
public static Thing<object> createThing() {...}
Fine, but now where do I put it?
IList<Thing<object>> list=new List<Thing<object>>();
Thing<object> thing=createThing();
list.Add(thing);
Yes, I have to say that this is a list of Thing with T of type Object, because C# has no wildcard type.
If this were Java, I'd simply say:
public class Thing<T> {...}
public static <T> Thing<T> createThing() {...}
List<?> things=new ArrayList<Thing<?>>();
Thing<?> thing=createThing();
things.add(thing);
If I wanted extra safety by saying that T had to be of a special type, I'd say:
public static <T extends MyBaseType> Thing<T> createThing() {...}
List<? extends MyBaseType> things=new ArrayList<Thing<? extends MyBaseType>>();
Thing<? extends MyBaseType> thing=createThing();
things.add(thing);
Then I'd figure out what T is later, when I had more information.
This all seems to come down to incomplete generic covariance in C# coupled with the lack of C# generic wildcards. (I still maintain it isn't an erasure issue.)
So what do I do? The only simple thing to do seems to follow Reinderien's answer and split out a non-generic base class.
(I wonder if in this non-generic base class I could have object getValue() and then use covariance in the subclass to return T getValue()? Ack, I'm tired of this---I'll leave that for another day.)

Categories

Resources