【问题标题】:Does .NET JIT compiler generate different code for generic parameterized with different enums?.NET JIT 编译器是否为使用不同枚举参数化的泛型生成不同的代码?
【发布时间】:2026-01-31 06:50:01
【问题描述】:

如果我编写(或使用)一个泛型类,例如列出,并用两种不同的枚举类型对其进行参数化,我会得到两份 JITted 代码吗?鉴于以下文章讨论了 JITter 如何为引用类型生成一个副本,以及为每个值类型生成一个副本,我认为这可以归结为,“每个特定的枚举是否被认为是 JITting 的不同值类型?”

CLR vs JIT

http://msdn.microsoft.com/en-us/library/ms379564%28v=vs.80%29.aspx#csharp_generics_topic1

在 C# 代码中:

using System.Collections.Generic;

namespace Z
{
    class Program
    {
        enum A {a}
        enum B {b}
        class C<T>
        {
        }

        static void Main(string[] args)
        {
            var x = new C<A>();
            var y = new C<B>(); // does this JIT a new C constructor for enum type B?
        }
    }
}

我很想知道这一点,但也专门针对 .NET CF 3.5 (WindowsCE) JIT 编译器(编辑:因为我对可能的代码膨胀影响感兴趣)。关于找出这个问题的最佳方法有什么建议吗?我正在考虑在 C 类中编写一个 P/Invokes 本机代码的函数,在那里我可以闯入调试器并检查调用堆栈 - 特别是返回地址,但也许有人可以根据我的语言规则权威地回答我不知道...

【问题讨论】:

  • 我猜每个底层整数类型只有一个实例化,但我很想听听权威的答案。
  • 是的。我们应该添加哪些标签来吸引 Eric Lippert 的注意?
  • fabulous-adventures-in-coding,我相信
  • 这更像是一个 CLR 问题而不是语言问题。乍一看,它看起来像是一个不属于 CLR 规范的实现细节,因为没有观察到行为上的差异。但从我的反射实验来看,枚举更像是一个包含底层 int 的结构,而不是 int 本身。

标签: .net generics enums jit


【解决方案1】:

所以我继续整理了一个 P/Invoke 函数,以便从 C.Test 函数中调用。我在本机函数中闯入调试器(支持托管和本机调试的桌面窗口),然后下降到程序集,然后从我的本机函数跟踪 RET 指令。 RET 之后的 EIP(指令指针)与返回两个不同的例程一致,一个用于 C.Test,另一个用于 C.Test。通过这两个函数多次调用通用本机函数(使用我的断点)显示了一致的结果。此外,后 RET EIP 是 0x2E0246 和 0x2E02BE,它们彼此靠近,也没有映射到加载的 DLL 的地址空间。这向我表明它们是 JITted,并且 JITted 在时间上彼此接近,并且 JITted 方法的大小很小(如预期的那样)。

因此,至少对于桌面而言,答案是使用不同枚举 JIT 对不同例程进行模板化的泛型。

【讨论】: