C# generic interface specialization

Overload resolution is performed at compile-time, not at run-time based on the actual type of the passed value.

IStorage i = new Storage();
i.Store("somestring"); // Prints Generic
i.Store(1); // Prints Generic

This will always call the "generic" method, because there is only one overload of Store in IStorage and the compiler doesn't know that i actually contains a Storage object. How can the compiler know about the other overload in Storage?

Storage s = (Storage)i;
s.Store("somestring"); // Prints Generic
s.Store(1); // Prints Specific

Here, the compiler knows that s contains a Storage object (or one deriving from Storage), because s is declared that way. So it sees two overloads. It chooses the specific overload for int values, because overload resolution rules say to prefer specific overloads over generic overloads.


It's technically possible to determine typeof(T) in the generic method at run-time and forward the method call to a specific method. But if you think about it, this doesn't make a lot of sense. A generic method means that the same implementation works for arguments of different, unrelated types. If you want different implementations for different types, you shouldn't use generics for this.


void Foo<T>(T t)
{
    SubFoo(t);
}

void SubFoo<T>(T t);
void SubFoo(int t);

Generics work quite a bit different from C++ templates. The C# compiler compiles Foo only once -- to a generic method. Remember: generic means same implementation for different types. The C# compiler does not know at compile-time if T is going to be an int or a string or any other type. So the only possible implementation of Foo that works for any T is to call SubFoo<T>. If one of the SubFoo overloads would be called depending on T, the implementation of Foo wouldn't be the same for all T any more.


Why Generic code-based specialization make a lot of sense in real world and in particular, in extension methods ?

I will take an example on collections because evrybody kowns more or less .NET collections.

I will take the simple example of the .Last(this IEnumerable<<T>> coll) extension method. In .NET Framework, this method use in-code type specialization.

First, concerning the benefit of type specialization, this example is quite clear. Some enumerable collections need to scan the whole collection and return the last element, array based one need only to return the last allocated element of the array, many linked list have a pointer to the last element... So implementing a generic with type specialization can make the .Last() method by far more efficient.

Second because this method is static, having many implementations for each collection type or interfaces wouldn't solve the problem of right method selection. In effect, selection of the right method is done at compile time based on apparent type of coll object. If you imagine, you want to apply consecutive extensions methods on a List<<T>>, the first one may not need many per collection type specialized implementations and use a single one based on IEnumerable<<T>>. So even if we have a .Last(this List<<T>> coll), the first non specialized extension method will return a IEnumerable<<T>> and the specialized .Last(this List<<T>> coll) will not be used for the List<<T>>.

So if your code use external assemblies (even .NET Framework itself), if you have to provide a solution in two weeks to a complex architectural problem ... you leave the domain of the perfection to enter in the real world. And generic type specialization become an not to ignore option.

Tags:

C#