我还没有研读《CLR Via C#》之类的专著,只是心里有了疑问,然后就去个人探究,下文多为猜想。更希望了解内幕的朋友告知C#后台真相。
我自个儿琢磨出来的结论:形如
1 // 原始声明 2 struct People : IFormattable 3 { 4 public string ToString( string format, IFormatProvider formatProvider) 5 { 6 return ToString(); 7 } 8 public override string ToString() { return Name; } 9 10 public string Name { get ; set ; } 11 }
的结构声明,会被转化为两个后台声明:
1 // 实际代码中的struct People 被映射成这个类型,虚方法声明和接口继承都无效了 2 struct PeoplePOD // : IFormattable 3 { 4 public string ToString( string format, IFormatProvider formatProvider) 5 { 6 return ToString(); 7 } 8 public /* override */ string ToString() { return Name; } 9 10 public string Name { get ; set ; } 11 } 12 // 这是装箱后的堆对象类型,任何试图将原始struct转化为object/ValueType/接口的转型,都会被自动装箱为这个类型的对象 13 class PeopleBox : IFormattable 14 { 15 public string ToString( string format, IFormatProvider formatProvider) 16 { 17 return ToString(); 18 } 19 public override string ToString() { return Name; } 20 21 public string Name { get ; set ; } 22 }
代码中出现的所有struct People,其实都是struct PeoplePOD,即放弃了虚函数和接口继承后的纯数据+非虚方法。没有了虚方法,对象实例中就不需要为了支持多态而去包含指向类型信息的指针,故对这个struct取sizeof得到的大小等于各个字段(不包括class字段)sizeof大小之和。
而任何将原始struct对象进行向基类的转换,都会造成装箱,装箱类型就是PeopleBox:
1 People orgin = new People(); 2 object _object = orgin; // object _object = new PeopleBox(orgin); 3 ValueType _valueType = orgin; // ValueType _valueType = new PeopleBox(orgin); 4 IFormattable _iformattable = orgin; // IFormattable _iformattable = new PeopleBox(orgin);