This question already has an answer here:
Closed 7 years ago.
First of all, sorry for the title, but I couldn't think about anything better ...
My problem can be presented by simple code sample:
public static class Test<T>
{
public static int GetInt(T source)
{
return Convert.ToInt32(source);
}
}
public static class Convert
{
public static int ToInt32(byte source)
{
return 30;
}
public static int ToInt32(object source)
{
return 10;
}
}
Why does Console.WriteLine(Test<byte>.GetInt(20));
prints 10
, instead of 30
?
I always thought that generics in .NET are resolved by JIT during runtime. Why then jitter isn't smart enough, to find out that there is ToInt32(byte)
method, which suits our byte
parameter type here?
This behavior makes Convert
static class methods call result in boxing/unboxing operations for simple types.
The compiler has to decide at compile time which method to choose. It doesn't emit any code to decide at runtime which of the two overloads to pick. Because you haven't provided any evidence to the C# compiler that GetInt(T source)
only works with byte
structures, the compiler has to pick the other overload.
Or let me put it in a different perspective: if you remove the ToInt32(object)
overload, your program fails to compile.
Compiler decides at compile time which method to execute.
I see through Reflector for IL code and found this -
.method public hidebysig static int32 GetInt(!T source) cil managed
{
.maxstack 1
.locals init (
[0] int32 CS$1$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: box !T
L_0007: call int32 ConsoleApplication1.Convert::ToInt32(object) <-- HERE
L_000c: stloc.0
L_000d: br.s L_000f
L_000f: ldloc.0
L_0010: ret
}
As mentioned by Jon Skeet here, you can make a call to byte method using dynamic
which provides typed information at execution time instead of compile time.
public static class Test<T>
{
public static int GetInt(T source)
{
dynamic dynamicSource = source;
return Convert.ToInt32(dynamicSource );
}
}