【问题标题】:Strange generic behaviour奇怪的通用行为
【发布时间】:2011-07-13 12:33:35
【问题描述】:

在以下代码中,发生了装箱(在 Generic.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()
        {
            Console.WriteLine(value);
        }
    }
}

ILSpy 输出:

.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

这是装箱和调用 Console.WriteLine(object)。我假设它会简单地调用 Console.WriteLine(string)。这是怎么回事?

【问题讨论】:

  • 看起来它使用了一些代码重用。
  • 仅供参考,调用泛型参数Type 是不好的做法,因为它可能与System.Type 冲突。

标签: c# .net generics


【解决方案1】:

不,它实际上不会装箱。来自box指令的ECMA-335描述:

如果 typeTok 是引用类型,则 box 指令确实将 val 返回为 obj

换句话说,box 在引用类型上调用它是无害的。

(无论如何,JIT 都会为引用类型和值类型生成单独的本机代码,所以我怀疑这最终会在引用类型版本中被完全删除。)

【讨论】:

  • +1 是的,我在第 4.1 节看到了这一点。 '确实返回',他们需要一些证明读者:P
【解决方案2】:

它为Console.WriteLine 选择了object 重载,因为这是最适合该调用的重载。

请记住,重载解析是在编译时完成的 - 编译器必须根据提供的类型信息选择合适的重载,在这种情况下,唯一合适的是object 重载。

要理解这一点,忽略您的Main 方法并考虑Generic 类位于不同程序集中的情况可能会有所帮助。编译器需要选择一个重载并且只知道Type 可以被强制转换或装箱为object。仅仅因为 实际上在程序集中的其他地方使用带有 string 类型参数的类的代码不会影响 Generic 的编译方式。

或者考虑如果Console.WriteLine 没有接受object 的重载会发生什么 - 在这种情况下,该方法根本无法编译(因为对Type 没有限制,这将使另一个重载适合) .

【讨论】:

  • 谢谢。您的回答解决了我的问题的一部分,而 Jon Skeet 的回答解决了另一部分,但我只能选择一个接受的答案。由于您的回答涉及我稍微关心的部分,因此我选择了您的回答。但是,所有答案都很有帮助。
【解决方案3】:

看起来像它的重用代码。

你可以试着强迫它不要那样做。

public void Print<Type>()
{
   Console.WriteLine(value);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-03
    • 2015-09-13
    • 1970-01-01
    相关资源
    最近更新 更多