代码:
    int i = 10;
    object obj = i;
    MessageBox.Show(obj.GetType().Name);
    显示是"Int32",只是为什么?不是已经装箱了吗?为什么类型没变?希望大哥大姐给出详细答案。

解决方案 »

  1.   

    这个结果是正确的,i确实已经装箱了,但是在解析其类别的时候,又自动拆箱获取其类型了。
    object是所有类型的祖先类型。打个比方:int i 是一个人
    object obj 是一个动物类
    你可以把人装箱成一个动物,那么现在这个箱子里装的就是一个人了,所以这个时候,我问你箱子里装的什么?你怎么回答??你会回答装的是人,不错,那么现在obj.GetType().Name获取的就是人。不知道你可理解了??
      

  2.   

    本帖最后由 caozhy 于 2011-08-21 11:20:08 编辑
      

  3.   

    i 的类型就是 int32 啊
      

  4.   

    int i装箱之后的到的那个object o确实不是个int
    是一个内置类型,我们不需要知道的
    这个内置类型应该有至少两个成员
    class InternalBoxedType{
        Type boxedType; // 记录被装箱变量的类型
        Value value;    // 记录被装箱变量的值
        
        publi void GetType(){
            return this.boxedType;
        }
    }
    这个内置类型也肯定重写了GetType()方法,但是他的GetType方法返回的不是typeof(InternalBoxedType)
    他返回的却是他装箱的变量的类型
      

  5.   


    这个就给lz之所以提出这个问题做了一个注脚吧。这是完全错误的,所以会产生这类问题。
    #2楼已经做出了解释。正如它所说,假设你用object类型的变量x指向一个具体的对象,x.GetType()当然返回的是具体对象的具体类型了,这是一个常识。同样地,如果你用Control类型的变量y引用一个TextBox控件,y.GetType()返回的当然也是TextBoxe而不是Control啦,这也是一个常识。引用变量总是引用具体的对象,对变量执行.GetType()怎么会返回定义变量时的类型呢?所谓object obj = i;装箱,它就是在堆中创建一个整数对象,并且把当前程序数据栈上面的i复制给它,然后使用一个引用变量obj指向这个新的对象。这就是装箱。而所谓的拆箱其实非常简单,意思就是不是从栈而是从堆中去读取这个整数值。
      

  6.   

    你不妨试试看改变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的操作?
      

  7.   

    楼主的疑问不是这些什么引用不引用的他的疑问在于,变量被装箱到堆了,为何程序依然会记得那块区域是一个int而不是一个float或者其他另外,你作为一个5星得选手应该知道虚函数的实现原理
    仅仅将一个int类型的10放入堆是复发实现GetType的多态行为的。
    要想多态,他必须有一个虚函数表的指针
      

  8.   


    第一次看到这样的解释,虽然装箱拆箱对性能有所影响,但很难想象如果CLR真的像上面这样来做的话,我想就不是对性能有所影响那么简单了
      

  9.   

    http://msdn.microsoft.com/en-us/library/25z57t8s(v=vs.80).aspx我这样说只是为了解释方便,况且说不定CLR的实现比这个还复杂另外复杂跟性能低是两回事至少,在unboxing的时候,必须知道boxing前变量的类型,所以boxing的时候必须要记录变量类型问题还不止这个呢,不同的值类型有不同的大小,这也是要考虑的问题
      

  10.   

    +1lz明明问的是为什么装箱后调用GetType方法,得到的却是Int32。5l说了一大堆,我都没看懂回答的到底是什么原因。说只是说是一个常识,我却不明白为什么是一个常识。C#里面为什么不返回变量的当前type,为什么一定要返回装箱前变量的类型。如果说是一个规定,我可以接受。说是一个常识,嘿嘿
      

  11.   


    变量声明后,其实就决定了汇编里是送32位寄存器还是送16位的,在此之前CLR会对常量进行溢出检查的。需要你考虑什么不同的大小?你只要考虑long和int之类的“兼容”就好了
      

  12.   

    你说的那是栈上的值类型的变量,所有的操作都是硬编码的,编译器自然知道栈上放的是什么,占用几个字节堆里放着一个变量,而且你是用一个object引用来指向他
    你就执行个object.GetType(),编译器怎么知道你想调用的是哪个GetType方法?
      

  13.   

    原因是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的构造方法,它使用的就是那个未确定类型的指针,构造之后就可以得到那个指针的特定类型(上面是整型)
      

  14.   

    丢人了
    我原本以为GetType是一个虚方法
    却发现他居然不是。也就是说我们不管在哪里调用这个GetType,都是一样的真扯淡
      

  15.   

    也就是说我们在任何地方调用的GetType,都是同一个,而且这个GetType还不是用C#实现的,反射不到
      

  16.   

    上面反射出来的是unsafe代码,最底层的代码的确看不到,IL中也是,到最后一个方法也看不到了