勤学似春起之苗,不见其增,日有所长; 辍学如磨刀之石,不见其损,日所有亏!
上次写的一篇关于ref和out关键字的问题,算是自我反省了一次。不过我觉得学习就应该有一种不怕挫折的的精神。继续学习,继续写文章。这次讨论一下boxing和unboxing问题,这是我今天在一论坛上看到的问题(源文代码):
posted on 2006-03-02 16:32 Wu.Country@侠缘 阅读(1549) 评论(13) 编辑 收藏
我还以为深入浅出MFC呢,请看http://a-z.cnblogs.com/archive/2006/02/08/327218.html 回复 引用 查看
哦。。。。。。。可能程序员对深入浅出MFC都很了解吧。。。呵呵,偷个关键字。 你的那篇文章在你POST的时候我就看了一遍的,但我没学过汇编,所以有一些看不明白。有时间我还会看一下的。 我还仔细看了一下关于boxing与unboxig之间的问题,看作者说的比我理解的清楚多了,谢谢了。 回复 引用 查看
如果说关于ref和out关键字的问题应该反醒的话,我觉得这里好像是犯了一个同样的错误。我认为对于boxing与unboxing,值类型和引用类型是一样的,楼主之所以在第二个测试中得出“boxing与unboxing在引用类型数据上没有起到作用”的结果,是因为将“更改变量”与“更改变量的成员”未正确区分造成的。看如下代码: using System; using System.Collections.Generic; using System.Text; namespace ConsoleApp { class Program { static void Main(string[] args) { TempClass modelTmp1 = new TempClass(); modelTmp1.Name = "Model1"; TempClass modelTmp2 = new TempClass(); modelTmp2.Name = "Model2"; TempClass tmp1 = modelTmp1; object obj1 = (object)tmp1; TempClass tmp2 = (TempClass)obj1; tmp2 = modelTmp2; Console.WriteLine("tmp1.Name:{0}",tmp1.Name); Console.WriteLine("obj1.Name:{0}", ((TempClass)obj1).Name); Console.WriteLine("tmp2.Name:{0}", tmp2.Name); Console.ReadLine(); } } class TempClass { private string name; public string Name { get { return name; } set { name = value; } } } } 运行的结果将是: tmp1.Name:Model1 obj1.Name:Model1 tmp2.Name:Model2 显然,对于引用类型,boxing+unboxing的结果同样不是原来的引用。 回复 引用 查看
这回引用关系分析得不错,呵呵。引用类型根本没有装箱的概念。 回复 引用 查看
谢谢,呵呵,多谢你上次的耐心解释呀。。。。。。 回复 引用 查看
装配脑袋说的对:引用类型是没有装箱概念的。引用《C#高级编程》里的一句话:封箱和拆箱可以把值类型转换为引用类型,或把引用类型转换为值类型。 在侠缘的这篇文章里,我们可以暂且把装箱理解为“从子类到父类的转换”,把拆箱理解为“从父类到子类的转换”。我上一篇回复的意思是:将一个值类型变量装箱,再拆箱后赋给另一个变量,这两个变量是相互独立的,只是他们存储的值相同而已,这完全没有问题,修改其中任一个变量的值自然不会引起另一个变量的值发生变化。将一个引用型变量“装箱”,再“拆装”后赋给另一个变量,这两个引用类型的变量同样是独立的,只是由于引用类型变量的特性,他们不是具有相同的“值”,而是“指向同一个实例的引用”,修改其中任何一个变量(当然还是修改引用),同样不会引起另外一个变量发生变化。总之,这是值类型与引用类型的区别,与boxing或unboxing是无关的。说白了,这和下面这段代码的意思是一样的: int v1=1; int v2=v1; v2=2; TempClass r1=new TempClass(); TempClass r2=r1; r2=new TempClass(); 我是这样理解的,可能有不当之处,欢迎大家共同讨论。做技术嘛,就需要这样,是吗? 回复 引用 查看
我明白你的意思了, 你的意思是说:上面例子里,修改unboxing之后的tmp1或者tmp2与修改unboxing之后的值类型是一样的,只不过一个修改的是引用的地址值,另一个是修改的实际数据值。而我的文章例子里没有修改引用地址值,而是修改的引用的实例的成员值。所以你提出了你的问题。对吧!? 其实明白是什么意思及概念就行了。 我的文章是想说明,本来通过boxing后,对于值类型,再unboxing回来,是不能修改boxing后的值的。但如果利用了接口,是可以用接口来修改boxing后的值类型数据的。谢谢你提出的讨论。希望对阅读的朋友们都有帮助,不至于像我那样犯错误了。呵呵。。。 回复 引用 查看
OK! 回复 引用 查看
其实了解boxing和unboxing对提高你的程序的性能是有很大帮助的。 比如: Int32 x = 12345; System.Console.WriteLine(x); 和 Int32 x = 12345; System.Console.WriteLine(x.ToString()); 这两行代码虽然结果一样,但是第一个例子会产生boxing操作,而第二个例子则不会。 Sheva 回复 引用 查看
是呀,应该多明白一些隐式的操作。而且新装箱与拆箱在本地CPU上也很浪费的,在A.Z的给出的文章里说的很清楚,大家可以看一下关于装箱与拆箱方面的内容。 回复 引用 查看
差点被楼住搞晕了。再吧jeffrey的书翻了一下,又清晰了。我的总结就是box和unbox操作是对于值型和引用型的相互转换,所以引用型与引用型是不需要box和unbox的。对于这一点发现侠缘的一个错误: Student stu=new Student("axiang"); Object o=(Object)stu;//boxing Student stu1=(Student)o;//unboxing stu1.Name="andy"; stu=(Student)o; Console.WriteLine(stu.name);//what would be written? IStudent istu=(IStudent)o;//unboxing ★ istu.Name="andychan"; stu=(Student)o; Console.Write(stu.name);//what would be written? now ★这里并没有unbox。因为接口是引用型。可以看汇编代码: .locals init ([0] valuetype Student stu, [1] object o, [2] valuetype Student stu1, [3] class IStudent istu) ......//省略 IL_0043: ldloc.1 //这里开始执行★处指令:拿到o IL_0044: castclass IStudent //注意没有unbox,仅仅是一个映射,istu和o指向同一个地方 IL_0049: stloc.3 //保存istu,操作完成 IL_004a: ldloc.3 IL_004b: ldstr "andychan" IL_0050: callvirt instance void IStudent::set_Name(string) ....//省略 IL_006d: ret 以前比较清楚,很久没看就模糊了,这下游比较清楚了。谢谢侠缘的文章。 回复 引用 查看
谢谢“一唯”的说明。 然而一开始我就没说 IStudent istu=(IStudent)o;是unboxing操作. [在此不得不承认代码里的注释错误//unboxing?。。向读者表示报谦了,然而全文从上到下都没有说上面是unboxing操作,仔细阅读的应该可以看明白我的本意。再次感谢“一唯”的说明。] "至于本文一开始的那段代码的结果,应该可以分析出来了,就是用struct来转时候,是一次内存的COPY,也就是unboxing,而用interface来转的时候,就只是一次引用的COPY,所以通过interface可以修改到boxing后的struct的数据。 " 注意:而用interface来转化的时候,就。。。。。。 下面这一段也明确说明了。 “其实这里已经不能说m_obj是值类型数据了,因为经过boxing,它已经成了引用类型。但由于它是用struct通过boxing过去的,所以再以struct身份unboxing回来的时候,都将会产生值类型unboxing的效果,也就是从栈上COPY一份数据到堆上,最终就是所有的数据修改都不会影响boxing后的引用数据。但是,如果用接口(interface)来处理的时候,就不会COPY内存,因为接口也是引用类型,这样在object与interface之间转化的时候,可以不COPY内存。我们就可以像上面的例子那样,用接口来来处理经过boxing的"值类型"数据。” 回复 引用 查看
Powered by: 博客园 Copyright © Wu.Country@侠缘