C#中值类型的继承以及方法重写对装箱的影响

hongfei233 2018-05-03 10:26:10
最近在看CLR via C#这本书关于值类型的拆箱和装箱有点疑惑,大概问题描述如下:
当调用一个值类型的ToString方法时,因为该值类型重写了ToString方法,加上值类型是封闭的,不能派生其他类型,所以当一个该值类型调用ToString方法时是不用执行装箱操作的。(CLR via C#一书第118页原文是“如果值类型重写了其中任何虚方法,那么CLR可以非虚的方式调用该方法,因为值类型隐式密封,不可能有其他类型从他们派生,而且调用虚方法的值类型没有实现装箱。然而,如果重写的虚方法要调用方法在基类中实现,那么再调用基类的实现时,值类型会实现装箱”)
红色文字描述有点模糊,绿色测试没问题;当我自定义一个结构之后,没有重写任何方法,分别调用ToString和GetType时,前者没有装箱,后者时有装箱的;测试代码和MSIL代码如下所示:
using System;
public sealed class Program1
{
public struct Tiny
{
public int m;
}

static void Main(string[] args)
{
Tiny t;
t.m = 3;
Console.WriteLine(t.ToString());
Console.WriteLine("-----------------------");
Console.WriteLine(t.GetType());

System.Console.Read();
}
}

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// Code size 63 (0x3f)
.maxstack 2
.locals init (valuetype Program1/Tiny V_0)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: ldc.i4.3
IL_0004: stfld int32 Program1/Tiny::m
IL_0009: ldloca.s V_0
IL_000b: constrained. Program1/Tiny
IL_0011: callvirt instance string [mscorlib]System.Object::ToString()
IL_0016: call void [mscorlib]System.Console::WriteLine(string)
IL_001b: nop
IL_001c: ldstr "-----------------------"
IL_0021: call void [mscorlib]System.Console::WriteLine(string)
IL_0026: nop
IL_0027: ldloc.0
IL_0028: box Program1/Tiny
IL_002d: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
IL_0032: call void [mscorlib]System.Console::WriteLine(object)
IL_0037: nop
IL_0038: call int32 [mscorlib]System.Console::Read()
IL_003d: pop
IL_003e: ret
} // end of method Program1::Main

后来查看ValueType类的结构之后,发现ValueType已经重写了Equals,GetHashCode和ToString,而GetType是Object类的公有非虚方法,不知道是不是可以理解为我自定义的Tiny结构因为隐式继承了ValueType类,而ValueType已经重写了ToString方法,所以代码中的t.ToString()是不会执行装箱操作的。
...全文
494 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
hongfei233 2018-05-03
  • 打赏
  • 举报
回复
确实翻译有点怪怪的,原文是:“Even though unboxed value types don’t have a type object pointer, you can still call virtual methods (such as Equals, GetHashCode, or ToString) inherited or overridden by the type. If your value type overrides one of these virtual methods, then the CLR can invoke the method nonvirtually because value types are implicitly sealed and cannot have any types derived from them. In addition, the value type instance being used to invoke the virtual method is not boxed. However, if your override of the virtual method calls into the base type's implementation of the method, then the value type instance does get boxed when calling the base type's implementation so that a reference to a heap object gets passed to the this pointer into the base method.
xuzuning 2018-05-03
  • 打赏
  • 举报
回复
1、没有必要深究这个问题,因为你经常不得不不把值类型当作对象使用 2、引用原文要是英文原版,而不是二百五的译文
exception92 2018-05-03
  • 打赏
  • 举报
回复
是不是可以理解为我自定义的Tiny结构因为隐式继承了ValueType类,而ValueType已经重写了ToString方法,所以代码中的t.ToString()是不会执行装箱操作的 -》是的,我觉得可以这样理解。 valuetype最终也是继承自object类,它提供的几个基础方法可以有派生类直接使用。而GetType 返回的是一个System.Type类类型,所以出现了装箱。

110,537

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧