开发者

Strange generic behaviour

开发者 https://www.devze.com 2023-03-20 12:21 出处:网络
In the following code, boxing occurs (in Generic<Type>.Print): using System; namespace Test { static class Program

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);
}
0

精彩评论

暂无评论...
验证码 换一张
取 消