It looks like in the following case the polymorphism does not work properly
I have the following definitions:
interface BaseInterface{}
interface NewInterface:BaseInterface{}
class NewClass:NewInterface{}
class GenericClass<T> where T:BaseInterface
{
public string WhoIAm(T anObject)
{
return TestPolymorphism.CheckInterface(anObject);
}
}
class ImplementedClass:GenericClass<NewInterface>{}
class TestPolymorphism
{
public static string CheckInterface(BaseInterface anInterface)
{
return "BaseInterface";
}
public static string CheckInterface(NewInterface anInterface)
{
return "NewInterface";
}
}
Then when I call :
NewClass nc = new NewClass();
ImplementedClass impClass = new ImplementedClass();
Console.WriteLine("The result is " + impClass.WhoIAm(nc));
I have “The result is BaseInterface”
I was expecting to have “The result is NewInterface” as nc implement BaseClass and NewClass
What would be the best way to get “NewClass” as the result ?
Thanks
Keep in mind with generic methods, that non-virtual method calls are still resolved at compile time of the generic itself, not at the compile time of the realization of the generic.
Thus this:
Will resolve to the overload that takes a
BaseInterfacebecause that’s what you’ve constrained it to regardless of the typeTactually is.Generics in C# aren’t quite like templates in C++, in C# generics, all reference types share the same code for the generic, thus they all treat the generic type similarly at compile time. This means that any compile time overloads your generic invokes using the generic type placeholder can only go by any constraints you provide on the generic type itself, since generics are compiled before they are actually realized.
That is, your
GenericClass<T>is compiled before any usage of it is considered (which is very different from the way C++ does templates — both methods have their pros and cons). So, if you have an unconstrained generic (say, justT) then it is consideredobjectfor the purposes of overloading (roughly speaking), but if you have a constrained generic (saywhere T : BaseInterface) then it is consideredBaseInterfacefor the purposes of overloading.You’d see something similar in this case:
So you’d think if you called this by:
Since
Tis typestringthen it would callstrings==overload, but it doesn’t, because you haven’t constrainedT, thus at compile time it assumes a least common denominator ofobjectand usesobjects==instead.Another way to think of this:
X will always say
BaseInterfacein the above, since overloads are resolved at compile time, not dynamically at run-time. Very similar to generics, just keep in mind that the generic is compiled before it is realized, so it can only go on whatever base class or interface you constrain it to for the purposes of overload resolution.