《CLR via C#(第三版)》中第124页。
using System;
internal struct Point{
private Int32 m_x,m_y;
public Point(Int32 x,Int32 y){ m_x=x;m_y=y; }
public void ChangePoint(Int32 x,Int32 y)
{ m_x=x;m_y=y; }
public override String ToString()
{ return String.Format("({0},{1})“,m_x,m_y); }
}
public sealed class Program
{
public static void Main(){
Point p=new Point(1,1);
Console.WriteLine(p);
p.Change(2,2);
Console.WriteLine(p);
Object o=p;
Console.WriteLine(o);
((Point)o).Change(3,3);
Console.WriteLine(o);
}
}
A、作者说在第一次调用WriteLine之前,p要进行封装,WriteLine会在已装箱的Point上调用ToString,并与其的那样显示(1,1)。【我就没弄懂为什么是在在WriteLine之前就封装了,不是在WriteLine的时候封装吗???】
我理解的是在WriteLine方法的时候进行了封装。 但是他的意思是在之前就封装了再WriteLine里面调用了ToString方法,这儿没有搞懂。。。
B、然后p调用Change方法,把m_xhe m_y都修改为2,第二次调用WriteLine时,要求再次对p进行封装,并预期的那样显示(2,2) 这个我可以理解的。
因为此时WriteLine使用的是 object 参数,那么在调用 WriteLine 之前,需要先把Point转换为Object类型。WriteLine只负责接收Object类型的参数,这个Object类型的参数是怎么得来的是不由WriteLine来管的。
“WriteLine会在已装箱的Point上调用ToString”
这句话没问题,装好箱,WriteLine才能调用ToString。
这名话并没有说在WriteLine语句执行之前进行装箱。
这里有一篇不错的图文并茂的装箱方面的文章:
确实是调用WriteLine之前进行的装箱,因为p是Point值类型,那么对应的WriteLine重载是:
public static void WriteLine(object value);
因此p被装箱,然后再作为参数传到WriteLine方法。如果你看生成的IL,就很清楚了,大概是这样子:
L_0003: initobj ConsoleApp.Program/Point L_0009: ldloc.0 L_000a: box ConsoleApp.Program/Point L_000f: call void [mscorlib]System.Console::WriteLine(object)
可以看出是先box操作,再call方法,并不是方法体具有装箱的职能。