关于C#装箱问题 代码: int i = 10; object obj = i; MessageBox.Show(obj.GetType().Name); 显示是"Int32",只是为什么?不是已经装箱了吗?为什么类型没变?希望大哥大姐给出详细答案。 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 这个结果是正确的,i确实已经装箱了,但是在解析其类别的时候,又自动拆箱获取其类型了。object是所有类型的祖先类型。打个比方:int i 是一个人object obj 是一个动物类你可以把人装箱成一个动物,那么现在这个箱子里装的就是一个人了,所以这个时候,我问你箱子里装的什么?你怎么回答??你会回答装的是人,不错,那么现在obj.GetType().Name获取的就是人。不知道你可理解了?? 本帖最后由 caozhy 于 2011-08-21 11:20:08 编辑 i 的类型就是 int32 啊 int i装箱之后的到的那个object o确实不是个int是一个内置类型,我们不需要知道的这个内置类型应该有至少两个成员class InternalBoxedType{ Type boxedType; // 记录被装箱变量的类型 Value value; // 记录被装箱变量的值 publi void GetType(){ return this.boxedType; }}这个内置类型也肯定重写了GetType()方法,但是他的GetType方法返回的不是typeof(InternalBoxedType)他返回的却是他装箱的变量的类型 这个就给lz之所以提出这个问题做了一个注脚吧。这是完全错误的,所以会产生这类问题。#2楼已经做出了解释。正如它所说,假设你用object类型的变量x指向一个具体的对象,x.GetType()当然返回的是具体对象的具体类型了,这是一个常识。同样地,如果你用Control类型的变量y引用一个TextBox控件,y.GetType()返回的当然也是TextBoxe而不是Control啦,这也是一个常识。引用变量总是引用具体的对象,对变量执行.GetType()怎么会返回定义变量时的类型呢?所谓object obj = i;装箱,它就是在堆中创建一个整数对象,并且把当前程序数据栈上面的i复制给它,然后使用一个引用变量obj指向这个新的对象。这就是装箱。而所谓的拆箱其实非常简单,意思就是不是从栈而是从堆中去读取这个整数值。 你不妨试试看改变obj变量的值 int i = 10; object obj = i; MessageBox.Show(string.Format("i={0}, obj=[1}",i,obj)); obj=20; MessageBox.Show(string.Format("i={0}, obj=[1}",i,obj)); 你可以看到,obj变量原来引用(堆上的)10现在引用(堆上的)20,而变量i则没有改变还是(栈上的)10。顺便也看看假设你对“装箱”做的解释,能不能以平常处理引用对象的基本知识,来解释给obj赋值以及各种各样的对引用变量obj的操作? 楼主的疑问不是这些什么引用不引用的他的疑问在于,变量被装箱到堆了,为何程序依然会记得那块区域是一个int而不是一个float或者其他另外,你作为一个5星得选手应该知道虚函数的实现原理仅仅将一个int类型的10放入堆是复发实现GetType的多态行为的。要想多态,他必须有一个虚函数表的指针 第一次看到这样的解释,虽然装箱拆箱对性能有所影响,但很难想象如果CLR真的像上面这样来做的话,我想就不是对性能有所影响那么简单了 http://msdn.microsoft.com/en-us/library/25z57t8s(v=vs.80).aspx我这样说只是为了解释方便,况且说不定CLR的实现比这个还复杂另外复杂跟性能低是两回事至少,在unboxing的时候,必须知道boxing前变量的类型,所以boxing的时候必须要记录变量类型问题还不止这个呢,不同的值类型有不同的大小,这也是要考虑的问题 +1lz明明问的是为什么装箱后调用GetType方法,得到的却是Int32。5l说了一大堆,我都没看懂回答的到底是什么原因。说只是说是一个常识,我却不明白为什么是一个常识。C#里面为什么不返回变量的当前type,为什么一定要返回装箱前变量的类型。如果说是一个规定,我可以接受。说是一个常识,嘿嘿 变量声明后,其实就决定了汇编里是送32位寄存器还是送16位的,在此之前CLR会对常量进行溢出检查的。需要你考虑什么不同的大小?你只要考虑long和int之类的“兼容”就好了 你说的那是栈上的值类型的变量,所有的操作都是硬编码的,编译器自然知道栈上放的是什么,占用几个字节堆里放着一个变量,而且你是用一个object引用来指向他你就执行个object.GetType(),编译器怎么知道你想调用的是哪个GetType方法? 原因是o是引用类型,i是值类型,它们的GetType是不一样的,看反射出来的代码[MethodImpl(MethodImplOptions.NoInlining)]public static Type GetType(string typeName){ StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller; return RuntimeType.PrivateGetType(typeName, false, false, ref lookForMyCaller);}internal static Type PrivateGetType(string typeName, bool throwOnError, bool ignoreCase, ref StackCrawlMark stackMark){ return PrivateGetType(typeName, throwOnError, ignoreCase, false, ref stackMark);}internal static RuntimeTypeHandle GetTypeByName(string name, bool throwOnError, bool ignoreCase, bool reflectionOnly, ref StackCrawlMark stackMark){ if ((name != null) && (name.Length != 0)) { return new RuntimeTypeHandle(_GetTypeByName(name, throwOnError, ignoreCase, reflectionOnly, ref stackMark, false)); } if (throwOnError) { throw new TypeLoadException(Environment.GetResourceString("Arg_TypeLoadNullStr")); } return new RuntimeTypeHandle();}internal unsafe RuntimeTypeHandle(void* rth){ this.m_ptr = new IntPtr(rth);}IntPtr 构造函数 (Void*)MSDN: IntPtr 结构用于表示指针或句柄的平台特定类型。其实关键就在后面的IntPtr的构造方法,它使用的就是那个未确定类型的指针,构造之后就可以得到那个指针的特定类型(上面是整型) 丢人了我原本以为GetType是一个虚方法却发现他居然不是。也就是说我们不管在哪里调用这个GetType,都是一样的真扯淡 也就是说我们在任何地方调用的GetType,都是同一个,而且这个GetType还不是用C#实现的,反射不到 上面反射出来的是unsafe代码,最底层的代码的确看不到,IL中也是,到最后一个方法也看不到了 “类库”作为“WCF服务”,寄宿在IIS7 源代码运行没问题,发布网站到服务器上运行出现这个问题,跪求答案 C# 如何在一个窗口中调用另外一个窗体的InitializeComponent方法? TabControl容器的问题! 求一个正则表达式 请教个datagirdiview控件的问题! c#调用c写dll出问题 Visual C#如何创建使用资源文件 Winform DataGridView中行灰显问题 如何控制文字输出到页面的格式~小弟把最后的分搭上了,还望能得到一个满意的答复! C# 制作WPF界面的一点小问题 请问Access数据库表里的字段名都是空格或斜杠,要怎么批量处理去掉呢?
object是所有类型的祖先类型。打个比方:int i 是一个人
object obj 是一个动物类
你可以把人装箱成一个动物,那么现在这个箱子里装的就是一个人了,所以这个时候,我问你箱子里装的什么?你怎么回答??你会回答装的是人,不错,那么现在obj.GetType().Name获取的就是人。不知道你可理解了??
是一个内置类型,我们不需要知道的
这个内置类型应该有至少两个成员
class InternalBoxedType{
Type boxedType; // 记录被装箱变量的类型
Value value; // 记录被装箱变量的值
publi void GetType(){
return this.boxedType;
}
}
这个内置类型也肯定重写了GetType()方法,但是他的GetType方法返回的不是typeof(InternalBoxedType)
他返回的却是他装箱的变量的类型
这个就给lz之所以提出这个问题做了一个注脚吧。这是完全错误的,所以会产生这类问题。
#2楼已经做出了解释。正如它所说,假设你用object类型的变量x指向一个具体的对象,x.GetType()当然返回的是具体对象的具体类型了,这是一个常识。同样地,如果你用Control类型的变量y引用一个TextBox控件,y.GetType()返回的当然也是TextBoxe而不是Control啦,这也是一个常识。引用变量总是引用具体的对象,对变量执行.GetType()怎么会返回定义变量时的类型呢?所谓object obj = i;装箱,它就是在堆中创建一个整数对象,并且把当前程序数据栈上面的i复制给它,然后使用一个引用变量obj指向这个新的对象。这就是装箱。而所谓的拆箱其实非常简单,意思就是不是从栈而是从堆中去读取这个整数值。
object obj = i;
MessageBox.Show(string.Format("i={0}, obj=[1}",i,obj));
obj=20;
MessageBox.Show(string.Format("i={0}, obj=[1}",i,obj));
你可以看到,obj变量原来引用(堆上的)10现在引用(堆上的)20,而变量i则没有改变还是(栈上的)10。顺便也看看假设你对“装箱”做的解释,能不能以平常处理引用对象的基本知识,来解释给obj赋值以及各种各样的对引用变量obj的操作?
仅仅将一个int类型的10放入堆是复发实现GetType的多态行为的。
要想多态,他必须有一个虚函数表的指针
第一次看到这样的解释,虽然装箱拆箱对性能有所影响,但很难想象如果CLR真的像上面这样来做的话,我想就不是对性能有所影响那么简单了
变量声明后,其实就决定了汇编里是送32位寄存器还是送16位的,在此之前CLR会对常量进行溢出检查的。需要你考虑什么不同的大小?你只要考虑long和int之类的“兼容”就好了
你就执行个object.GetType(),编译器怎么知道你想调用的是哪个GetType方法?
public static Type GetType(string typeName)
{
StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
return RuntimeType.PrivateGetType(typeName, false, false, ref lookForMyCaller);
}internal static Type PrivateGetType(string typeName, bool throwOnError, bool ignoreCase, ref StackCrawlMark stackMark)
{
return PrivateGetType(typeName, throwOnError, ignoreCase, false, ref stackMark);
}internal static RuntimeTypeHandle GetTypeByName(string name, bool throwOnError, bool ignoreCase, bool reflectionOnly, ref StackCrawlMark stackMark)
{
if ((name != null) && (name.Length != 0))
{
return new RuntimeTypeHandle(_GetTypeByName(name, throwOnError, ignoreCase, reflectionOnly, ref stackMark, false));
}
if (throwOnError)
{
throw new TypeLoadException(Environment.GetResourceString("Arg_TypeLoadNullStr"));
}
return new RuntimeTypeHandle();
}internal unsafe RuntimeTypeHandle(void* rth)
{
this.m_ptr = new IntPtr(rth);
}
IntPtr 构造函数 (Void*)
MSDN: IntPtr 结构用于表示指针或句柄的平台特定类型。其实关键就在后面的IntPtr的构造方法,它使用的就是那个未确定类型的指针,构造之后就可以得到那个指针的特定类型(上面是整型)
我原本以为GetType是一个虚方法
却发现他居然不是。也就是说我们不管在哪里调用这个GetType,都是一样的真扯淡