简体   繁体   English

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

[英]How can I avoid boxing when pass a struct value as an interface value?

Interface (I) is a reference type, struct (S) is a value type. 接口(I)是引用类型,struct(S)是值类型。 Structs can implement interfaces. 结构可以实现接口。

public interface I {}
struct S: I {}

Assume there is a value of S which is passed to a method as an argument of I. In this case it has to be boxed. 假设存在一个S值,它作为I的参数传递给方法。在这种情况下,它必须被加框。

void Method(I i) {}

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

Is there a way to avoid boxing in this case? 在这种情况下有没有办法避免拳击?

You can avoid boxing if you change the definition of Method to: 如果将Method的定义更改为:

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

This avoids boxing, because at runtime the CLR specialises generic methods based on the type of the generic argument(s). 这避免了装箱,因为在运行时,CLR根据通用参数的类型专门化泛型方法。 Reference types can all share the same implementation, while struct types each get their own version. 引用类型都可以共享相同的实现,而struct类型每个都有自己的版本。 This means all the operations in Method which depend on T will take into account the size of the concrete struct type. 这意味着Method中依赖于T所有操作都将考虑具体结构类型的大小。

You must be careful however, since calling virtual methods defined on System.Object like Equals or GetHashCode will cause i to be boxed since virtual method dispatch requires a method table pointer (although the JIT may be able to do the dispatch statically in some cases). 但是,您必须小心,因为调用System.Object定义的虚拟方法(如EqualsGetHashCode将导致i被装箱,因为虚方法调度需要方法表指针(尽管JIT可能能够在某些情况下静态执行调度) 。 However, if your struct type overrides the virtual method(s) in question, then boxing will not need to be done, since the method to call is again known statically since structs (and hence their members) are sealed. 但是,如果你的struct类型覆盖了有问题的虚拟方法,那么就不需要进行装箱,因为调用方法再次被静态地知道,因为结构(以及它们的成员)是密封的。

Usually you can avoid calling Equals or GetHashCode directly by constraining T further to implement IEquatable<T> and using an IEqualityComparer<T> for comparisons eg 通常,您可以通过进一步约束T来实现IEquatable<T>并使用IEqualityComparer<T>进行比较来避免直接调用EqualsGetHashCode ,例如

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

Use generics: 使用泛型:

public interface I {}
public struct S : I {}
public class Foo
{
    public static void Bar<T>(T i)
        where T : I
    {}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM