C# 在C中使用泛型时装箱#

C# 在C中使用泛型时装箱#,c#,generics,C#,Generics,我有以下简单的C代码: private Stack m_Stack=new Stack(); 公共无效添加(T obj) 式中T:人 { m_堆栈推送(obj); } 这将产生以下IL代码: .method public hidebysig instance void Add<(ConsoleApplication1.Person) T>(!!T obj) cil managed { // Code size 20 (0x14)

我有以下简单的C代码:

private Stack m_Stack=new Stack();
公共无效添加(T obj)
式中T:人
{
m_堆栈推送(obj);
}
这将产生以下IL代码:

  .method public hidebysig instance void 
          Add<(ConsoleApplication1.Person) T>(!!T obj) cil managed
  {
    // Code size       20 (0x14)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldfld      class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person> ConsoleApplication1.Pool::m_stack
    IL_0007:  ldarg.1
    IL_0008:  box        !!T
    IL_000d:  callvirt   instance void class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person>::Push(!0)
    IL_0012:  nop
    IL_0013:  ret
  } // end of method Pool::Add
.method公共隐藏实例void
添加(!!T obj)cil管理
{
//代码大小20(0x14)
.maxstack 8
IL_0000:没有
IL_0001:ldarg.0
IL_0002:ldfld类[System]System.Collections.Generic.Stack`1 ConsoleApplication1.Pool::m_Stack
IL_0007:ldarg.1
IL_0008:box!!T
IL_000d:callvirt实例无效类[System]System.Collections.Generic.Stack`1::Push(!0)
IL_0012:没有
IL_0013:ret
}//方法池结束::添加
所以我的问题是。。。为什么是拳击?(IL_0008)我可以理解向下转换甚至编译错误,但为什么装箱(Person是引用类型…)


提前谢谢

我相信这是通用方法约束对您造成的影响-但是

无论如何,根本不需要泛型方法。就这样写吧:


公共无效添加(个人)
{
m_堆栈推送(人);
}

你会发现IL得到了简化,完全避免了这个问题。如果要约束到特定的引用类型,则可以只使用该引用类型


这更容易理解,也更清晰。我建议避免泛型方法调用,除非确实需要。泛型方法使类不那么明显,这意味着从长远来看可读性和可维护性较差,使用起来也更困难。

摘自Ecma-335 Partition III 4.1

如果typeTok是引用类型,则box指令不执行任何操作

typeTok在哪!!就你的情况而言,这是不可能的


我的猜测是,当编译器编译代码时,无论操作数的类型是否为引用类型,它总是调用box。由于box指令的语义,期望的结果总是有保证的。

@Reed:是的,这就是我解决问题的方法,但我很好奇为什么引用类型是装箱的(没有任何意义)…我认为这是通用方法工作原理的实现。请注意,这是T,而不是人。您永远不会装箱/取消装箱您的类,但它是一些“额外”的东西,最终在泛型方法调用中出现。不知道为什么,不过。+1很好的工作跟踪这一点。好消息。那么,这条指令也会被JIT删除,还是会导致noop指令留在原地?
  .method public hidebysig instance void 
          Add<(ConsoleApplication1.Person) T>(!!T obj) cil managed
  {
    // Code size       20 (0x14)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldfld      class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person> ConsoleApplication1.Pool::m_stack
    IL_0007:  ldarg.1
    IL_0008:  box        !!T
    IL_000d:  callvirt   instance void class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person>::Push(!0)
    IL_0012:  nop
    IL_0013:  ret
  } // end of method Pool::Add
public void Add(Person person) { m_stack.Push(person); }