c# – 当将struct值作为接口值传递时,如何避免装箱?

接口(I)是引用类型,struct(S)是值类型.结构可以实现接口.

public interface I {}
struct S: I {}

假设存在一个S值,它作为I的参数传递给方法.在这种情况下,它必须被加框.

void Method(I i) {}

void Test() {
   var s = new S();
   this.Method(s); // <---- boxing!
}

在这种情况下有没有办法避免拳击?

最佳答案
如果将Method的定义更改为:

void Method<T>(T i) where T : I
{
}

这避免了装箱,因为在运行时CLR根据通用参数的类型专门化泛型方法.引用类型都可以共享相同的实现,而struct类型每个都有自己的版本.这意味着Method中依赖于T的所有操作都将考虑具体结构类型的大小.

但是,您必须小心,因为调用System.Object上定义的虚拟方法(如Equals或GetHashCode)将导致i被装箱,因为虚方法调度需要方法表指针(尽管JIT可能能够在某些情况下静态执行调度) .但是,如果你的结构类型覆盖了有问题的虚方法,那么就不需要进行装箱,因为调用方法再次被静态地知道,因为结构(因此它们的成员)是密封的.

通常,您可以通过进一步约束T来实现IEquatable< T>来避免直接调用Equals或GetHashCode.并使用IEqualityComparer< T>用于比较,例如

void Method<T>(T i) where T : I, IEquatable<T>
{
    T other = ...
    if(i.Equals(other))    //avoids boxing
    {
    }
}

转载注明原文:c# – 当将struct值作为接口值传递时,如何避免装箱? - 代码日志