是否可以使用泛型在运行时导致装箱

本文关键字:运行时 可以使 泛型 是否 | 更新日期: 2023-09-27 17:50:16

在 Jon Skeet 的书"C# in Depth, Third Edition"中,我读到了这个

"所有这些都足以使泛型有价值,但也有性能改进。首先,由于编译器可以执行更多的强制,因此在执行时需要检查的内容更少。其次,JIT 可以以一种特别聪明的方式处理值类型,在许多情况下设法消除装箱和拆箱。

这是否意味着在某些情况下,仿制药可能会导致拳击?如果是,有人可以举个例子吗?

是否可以使用泛型在运行时导致装箱

调用

虚拟方法时需要装箱,因此以下情况将导致first被装箱:

public static bool Equals<T>(T first, T other) where T : struct
{
    return first.Equals(other);
}
bool eq = Equals(1, 2);

更改对T的约束可以防止装箱:

public static bool Equals<T>(T first, T other) where T : IEquatable<T>
{
   return first.Equals(other);
}

某些方法可以对装箱或未装箱结构进行操作,而其他方法只有在装箱时才能对结构进行操作。 如果一个方法持有一个装箱结构,它可以将其传递给需要装箱结构的方法,而不必装箱它。 相反,如果方法包含未装箱结构,则每次调用需要装箱结构的方法都需要单独的装箱操作。

考虑: 接口 是 嘟嘟 { 随便 }; 结构 傀儡 : IStooge { whatever};

void Moe(Stooge x)
{
  Larry(x);
}
void Larry<T>(T x) where T:IStooge
{
  for (int i=0; i<1000000; i++)
    Curly(x);
}
void Curly(IStooge x)
{ whatever; }

萌有一个未装箱的Stooge . 拉里可以使用实现IStooge的盒装或未装箱的东西。 Curly 只接受 IStooge 的盒装实现。

如果Moe将一个未装箱的Stooge传递给Larry,那么Larry将创建一个新的装箱Stooge,将数据从x复制到该,将对新对象的引用传递给Curly,然后放弃该新对象;然后它将重复该过程999,999次, 每次都以新的盒装Stooge开始。

如果Moe在传递x之前将其转换为IStooge,或者如果Larry(如Curly(是一个只接受IStooge的盒装实现的非泛型方法,那么x将在调用Larry之前被装箱。 在每次通过循环时,Larry都会Curly传递对已经装箱的Stooge的引用,而不必创建一个新的装箱实例。 净效果是,通过使Larry非通用或以非通用方式使用它,所需的装箱操作数量将大大减少。

在仿制药可以消除拳击的情况下(他们通常可以(,他们自然会减少拳击。 然而,在最终需要拳击的情况下,通常最好在外部范围内而不是嵌套范围内进行。 泛型通常防止在外部范围内进行装箱,这在可以完全防止的情况下是好的,但如果它最终将其从可以完成一次的地方移动到必须重复完成的地方,那就不是那么好了。

我相信

Jon 指的是为每个值类型编译泛型类型的新实例的事实。 如果你做List,List,List,它只有一个编译的类,因为它们都继承自对象。 如果您有 List、List 和 List,则每个类型都有一个单独的编译类型,由 JITter 创建。 这就是它避免拳击的方式,因为它没有将其放在列表中。

对于你的第二个问题,我不知道它保证没有运行时装箱,但在类的一般使用中,应该消除它。

相关文章: