在Jon Skeet的书“C#in Depth,Third Edition”中我读到了这个
“所有这些都足以使泛型变得有价值,但也有性能改进。首先,因为编译器可以执行更多强制执行,所以在执行时需要检查更少。其次,JIT可以处理值以一种特别聪明的方式设置类型,以便在许多情况下消除装箱和拆箱 。“
这是否意味着在某些情况下仿制药会导致拳击?如果是,有人可以举个例子吗?
答案 0 :(得分:2)
调用虚拟方法时需要进行装箱,因此以下内容会导致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);
}
答案 1 :(得分:1)
某些方法可以在盒装或非盒装结构上运行,而其他方法只有在盒装时才能在结构上运行。如果方法包含盒装结构,则可以将其传递给需要盒装结构的方法,而不必将其装箱。相比之下,如果方法包含未装箱的结构,每次调用需要盒装结构的方法都需要单独的装箱操作。
考虑: 界面IStooge {whatever}; struct Stooge: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; }
Moe有一个未装箱的Stooge
。 Larry可以使用实现IStooge
的盒装或未装箱的东西。 Curly只接受IStooge
的盒装实现。
如果Moe
将未装箱的Stooge
传递给Larry
,则Larry
将创建一个新的装箱Stooge
,从{{1}复制数据对此,将对象的引用传递给x
,然后放弃该新对象;然后,它将重复该过程999,999次,每次使用新的方框Curly
开始。
如果Stooge
在传递之前将Moe
投射到x
,或者IStooge
是Larry
(如Curly
),那么只有非通用方法接受IStooge
的盒装实施,然后在调用x
之前将Larry
装箱。在每次循环传递时,Larry
会将Curly
引用传递给已经装箱的Stooge
,而不必创建新的盒装实例。最大的影响是,通过使Larry
非通用或以非通用方式使用它,所需的装箱操作数量将大大减少。
在仿制药可以消除拳击(他们通常可以)的情况下,他们自然会减少拳击。然而,在拳击最终是必要的情况下,通常最好在外部范围而不是嵌套范围内进行。泛型通常会阻止外部范围内的装箱,这在可以完全防止的情况下是好的,但是如果最终将它从可以在某个地方移动到某个地方的地方移动它就不会那么好,它将不得不重复进行。 / p>
答案 2 :(得分:-1)
我相信Jon指的是为每个值类型编译一个Generic类型的新实例。如果你做List,List,List,它只会有一个编译类,因为它们都是从object继承的。如果你有List,List和List,那么JITter创建的每一个都有一个单独的编译类型。这就是它如何避免拳击,因为它没有把它放在列表中。
对于你的第二个问题,我不知道它保证没有运行时装箱,但是在一般使用该类时,它应该被淘汰。