结构体转父接口时的装箱疑问:as关键字是否影响装箱?
C#值类型转接口的装箱与
as关键字的真相 首先给你明确结论:myStruct as IA照样会触发装箱,Rider的无装箱警告是个误导性提示。
核心原因拆解
C#里值类型(比如你定义的SA结构体)实现接口后,只要把它传给接口类型的参数,不管是隐式传递还是用as显式转换,CLR都必须对这个值类型实例执行装箱操作——因为接口属于引用类型,值类型本身没有引用类型的对象头,必须被包装到一个对象实例中,才能匹配接口参数的类型要求。
Rider提示as IA是冗余转换,这个判断是对的:因为SA已经实现了IA,这个转换语法上完全没必要;但它声称“无装箱”就是错的——不管你写不写as,装箱都会发生。你可以查看编译后的IL代码验证,两行调用都会生成box SA指令,这就是装箱的实锤。
真正避免装箱的方案
靠as这种语法糖解决不了装箱问题,得换写法:给Foo新增泛型重载,利用泛型特化特性规避装箱:
public interface IA{} public struct SA: IA{} public class SomeClass { // 保留原接口版本,兼容现有调用 public void Foo(IA param) { } // 新增泛型版本,约束为IA public void Foo<T>(T param) where T : IA { // 此处操作param不会触发装箱,值类型会生成特化的方法实现 } public void Bar() { SA myStruct = new SA(); Foo(myStruct); // 现在调用泛型版本,无装箱、无警告 } }
若仅需屏蔽Rider警告
要是你不在乎装箱开销,只是不想看到Rider的提示,别用as自欺欺人,直接用Rider的注释屏蔽警告更直白:
SA myStruct = new SA(); // ReSharper disable once BoxingAllocation Foo(myStruct);
或者直接接受这个警告——如果这段代码不是高频调用的性能敏感路径,装箱的开销完全可以忽略。
内容的提问来源于stack exchange,提问作者QuestionsGuy
相关产品推荐
相关产品推荐

