I wonder if it is in any way possible to specialize generic interface methods somehow in C#? I have found similar questions, but nothing exactly like this. Now I suspect that the answer is “No, you can’t” but I would like to have it confirmed.
What I have is something like the following.
public interface IStorage
{
void Store<T>(T data);
}
public class Storage : IStorage
{
public void Store<T>(T data)
{
Console.WriteLine("Generic");
}
public void Store(int data)
{
Console.WriteLine("Specific");
}
}
class Program
{
static void Main(string[] args)
{
IStorage i = new Storage();
i.Store("somestring"); // Prints Generic
i.Store(1); // Prints Generic
Storage s = (Storage)i;
s.Store("somestring"); // Prints Generic
s.Store(1); // Prints Specific
}
}
Is there any way to make it use the specialized version of Store when called through the interface? And if not, does anyone know the exact reason why C# treats Generic arguments this way?
Edit:
The issue could be worked around if it wasn’t so that C# cannot resolve template arguments in more than one step.
void Foo<T>(T t)
{
SubFoo(t);
}
void SubFoo<T>(T t)
{
Console.WriteLine("Generic");
}
void SubFoo(int t)
{
Console.WriteLine("Specific");
}
A call to Foo(1) here will print “Generic” as well, shouldn’t the compiler be able to resolve this? Or does the JIT prevent this?
Overload resolution is performed at compile-time, not at run-time based on the actual type of the passed value.
This will always call the “generic” method, because there is only one overload of
StoreinIStorageand the compiler doesn’t know thatiactually contains aStorageobject. How can the compiler know about the other overload inStorage?Here, the compiler knows that
scontains aStorageobject (or one deriving fromStorage), becausesis declared that way. So it sees two overloads. It chooses the specific overload forintvalues, 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.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
intor astringor 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.