c# - 将结构值作为接口(interface)值传递时如何避免装箱?

标签 c#

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

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 会根据泛型参数的类型专门化泛型方法。引用类型可以共享相同的实现,而结构类型各自有自己的版本。这意味着 Method 中的所有操作这取决于 T将考虑具体结构类型的大小。

但是你必须小心,因为调用在 System.Object 上定义的虚方法喜欢EqualsGetHashCode会导致i装箱,因为虚拟方法分派(dispatch)需要一个方法表指针(尽管在某些情况下 JIT 可能能够静态地进行分派(dispatch))。但是,如果您的结构类型覆盖了有问题的虚方法,则不需要进行装箱,因为由于结构(及其成员)是密封的,调用的方法再次静态已知。

通常你可以避免调用EqualsGetHashCode直接通过约束 T进一步落实IEquatable<T>并使用 IEqualityComparer<T>用于比较,例如

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

关于c# - 将结构值作为接口(interface)值传递时如何避免装箱?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17639886/

相关文章:

c# - 如何使用 Visual Studio 2010 将 Windows 控制台应用程序 C# 项目更改为 Windows 服务?

C# html 电子邮件 - Div/文本覆盖图像

c# - 不区分大小写的字符串搜索

c# - 锁定 .NET 与 Java 的成本

c# - 调试 C# 中的 VS 与 SQL Server 之间的连接

c# - (this == null) 在 C# 中!

c# 异步方法中的阻塞代码

c# - WPF:如何将通用数据绑定(bind)到 TreeView?

c# - 自动生成 .NET 单元测试

c# - 在 JsonConverter.ReadJson() 中有效地获取完整的 json 字符串