In the following code, boxing occurs (in Generic<Type>.Print):
using System;
namespace Test
{
static class Program
{
static void Main()
{
Generic<string> generic = new Generic<string>("test");
generic.Print();
}
}
class Generic<Type>
{
Type value;
public Generic(Type value)
{
this.value = value;
}
public void Print()
{
开发者_StackOverflow中文版 Console.WriteLine(value);
}
}
}
ILSpy output:
.method public hidebysig
instance void Print () cil managed
{
// Method begins at RVA 0x207d
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld !0 class Test.Generic`1<!Type>::'value'
IL_0006: box !Type
IL_000b: call void [mscorlib]System.Console::WriteLine(object)
IL_0010: ret
} // end of method Generic`1::Print
It's boxing and calling Console.WriteLine(object). I assumed that it would simply call Console.WriteLine(string). What is going on here?
Nope, it won't actually box. From the ECMA-335 description of the box
instruction:
If typeTok is a reference type, the box instruction does returns val unchanged as obj.
In other words, a box
is harmless if you call it on a reference type.
(The JIT will be generating separate native code for reference types and value types anyway, so I suspect this just ends up being completely removed in the reference type version.)
Its chosen the object
overload for Console.WriteLine
because this is the most appropriate overload for that call.
Remember that overload resolution is done at compile time - the compiler must choose a suitable overload based on the provided type information, and in this situation the only suitable one is the object
overload.
To understand this it may help to ignore your Main
method and consider the case where the Generic
class is in a different assembly. The compiler needs to choose an overload and knows only that Type
can either be cast or boxed into an object
. Just because there is in fact code elsewhere in the assembly that uses this class with a string
type parameter doesn't affect the way that Generic
is compiled.
Alternatively consider what would happen if Console.WriteLine
didn't have an overload accepting an object
- in this case the method simply would not compile (as there are no restrictions on Type
which would make another overload suitable).
Looks like its reusing code.
You could try to force it not to do that.
public void Print<Type>()
{
Console.WriteLine(value);
}
精彩评论