假如有一个
struct Piont
{
Int32 x;
Int32 y;
}struct是值类型,所以没有无参构造函数,但是却可以Point p = new Point();这样做算不算调用构造函数,如果是的话,这部分内存是在堆上分配的还是在栈上分配,按理说应该在堆上分配吧!Point p = new Point();
p.x=1;
p.y = 1;Piont p1,
p1.x=1;
p1.y=1;这样p.Equal(p1)是true这点我觉得应该是System.ValueType重写了equals方法的缘故吧!主要是对Point p = new Point();这个new方法的使用,以及分配内存的位置有点不解,求高手解答!

解决方案 »

  1.   

    样做算不算调用构造函数 - 算
    这部分内存是在堆上分配的还是在栈上分配 - 栈上
    p.Equal(p1)是true这点我觉得应该是System.ValueType重写了equals方法 - 对
      

  2.   

    可是我使用ildasm查看中间代码,并未发现它有.ctor
      

  3.   

    是栈上分配的。class和struct最本质的区别就在于class是引用类型,内存分配于托管堆;而struct是值类型,内存分配于线程的堆栈上。
    struct(结构)是一种值类型,用于将一组相关的信息变量组织为一个单一的变量实体 。所有的结构都继承自System.ValueType类,因此是一种值类型,也就是说,struct实例分配在线程的堆栈(stack)上,它本身存储了值,而不包含指向该值的指针。所以在使用struct时,我们可以将其当作int、char这样的基本类型类对待。
      

  4.   

    值类型都分配在栈上,new 不new效果是一样的而引用类型new时,在堆上,计算了类型大小,外加同步索引快和类型对象指针。
      

  5.   

    另外说明一点...对值类型调用默认构造函数不是必需的,只有当struct用new实例化时才会调用默认构造函数...
      

  6.   

    class可以声明protected成员、virtual成员、sealed成员和override成员;而struct不可以,但是值得注意的是,struct可以重载System.Object的3个虚方法,Equals()、ToString()和GetHashTable()。 
      

  7.   


    这么说只要valuetype分配内存一定是在栈上,而与new无关了,new关心的只是分配内存而不关心在哪分配内存?
      

  8.   

    这个我知道,我现在的疑惑在于我查看了中间代码,并没有.ctor,能否给个解释
      

  9.   

    可是没有合理的理由,我只能相信眼镜看到的啊!并且我看CLR via C#上边说的
    In the Point value type defined earlier, no default parameterless constructor is defined
    也就是说它没有默认的无参构造了,既然如此怎么能Point p = new Point();这么使用,我最疑惑的是这个!
      

  10.   

    确实没有啊,我定义了一个struct和class在class里边是可以看到的,struct确实没有!
      

  11.   

    MSDN上讲得清清楚楚,怎么叫“没有合理的理由”?...不明确的地方要去看官方资料而不是人云亦云...http://msdn.microsoft.com/zh-cn/library/ms173115(VS.80).aspx
      

  12.   

    CLR并不要求值类型必须定义构造器方法,实际上C#编译器也不会为值类型产生默认的无参构造器。但CLR允许我们为值类型定义构造器,不能给值类型定义一个无参构造器。当我们使用构造器,只有我们显式调用构造器才会被执行,用new来创建一个值类型时,只是调用的他的构造器(而引用类型因为是分配在托管堆上,new的时候有3个步骤)。如果不使用new来创建,那么值类型的字段都会保持为0,在调用构造器之前系统为该对象分配的内存总是被设置为0。严格的说只有内嵌于引用类型的值类型字段,CLR才会保证字段被初始化为0或null,基于堆栈的值类型字段无法保证
      

  13.   

    public abstract class ValueType
    {
        // Methods
        protected ValueType()
        {
        }    public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            RuntimeType rt = (RuntimeType) base.GetType();
            RuntimeType type = (RuntimeType) obj.GetType();
            if (type != rt)
            {
                return false;
            }
            object obj2 = this;
            FieldInfo[] infoArray = RuntimeType.InternalGetFields(rt, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, false);
            for (int i = 0; i < infoArray.Length; i++)
            {
                object obj3 = RuntimeFieldInfo.InternalGetValue((RuntimeFieldInfo) infoArray[i], obj2, false);
                object obj4 = RuntimeFieldInfo.InternalGetValue((RuntimeFieldInfo) infoArray[i], obj, false);
                if (obj3 == null)
                {
                    if (obj4 != null)
                    {
                        return false;
                    }
                }
                else if (!obj3.Equals(obj4))
                {
                    return false;
                }
            }
            return true;
        }    public override int GetHashCode()
        {
            RuntimeType rt = (RuntimeType) base.GetType();
            FieldInfo[] infoArray = RuntimeType.InternalGetFields(rt, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, false);
            if (infoArray.Length > 0)
            {
                for (int i = 0; i < infoArray.Length; i++)
                {
                    object obj2 = RuntimeFieldInfo.InternalGetValue((RuntimeFieldInfo) infoArray[i], this, false);
                    if (obj2 != null)
                    {
                        return obj2.GetHashCode();
                    }
                }
            }
            return rt.GetHashCode();
        }
    }
    你看的是ValueType的源码么?
      

  14.   

    直接看IL就完了啊当值类型没有构造函数的时候,使用的是initobj 命令,这个命令会对象设置为0或null,而不调用构造函数
    当值类型有构造函数时,使用的是call,调用的是含参的构造函数而对于引用类型,他始终调用的是newobj命令默认值类型new确实是没有产生构造函数,因为用的是initobj 命令。还纠结啥?
      

  15.   

    谢谢!语气平和一点嘛!
    我想再问个问题,既然它有默认构造,为什么不像class那样,再中间语言里边可以看得到呢?
      

  16.   

        static void Main(string[] args)
        {
            MyPoint o = new MyPoint();
            MyPoint2 o2 = new MyPoint2();
            Console.ReadKey();
        }    public struct MyPoint
        {
            public int x;
            public int y;
        }    public class MyPoint2
        {
            public int x;
            public int y;
        }        MyPoint o = new MyPoint();
    00000035  lea         edi,[ebp-44h] 
    00000038  pxor        xmm0,xmm0 
    0000003c  movq        mmword ptr [edi],xmm0 
            MyPoint2 o2 = new MyPoint2();
    00000040  mov         ecx,569F08h 
    00000045  call        FFD40AD4 
    0000004a  mov         dword ptr [ebp-4Ch],eax 
    0000004d  mov         ecx,dword ptr [ebp-4Ch] 
    00000050  call        FFD5B068 
    00000055  mov         eax,dword ptr [ebp-4Ch] 
    00000058  mov         dword ptr [ebp-48h],eax 
      

  17.   

    不懂IL。但struct的的确没看到call
      

  18.   

        struct test2
        {
            public int x;
            public test2(int x)
            {
                this.x = x;
            }
        }
                test2 a = new test2();
                test2 b;
                b.x = 0;
                test2 c = new test2(0);
      IL_0000:  nop
      IL_0001:  ldloca.s   a
      IL_0003:  initobj    WindowsFormsApplication1.test2
      IL_0009:  ldloca.s   b
      IL_000b:  ldc.i4.0
      IL_000c:  stfld      int32 WindowsFormsApplication1.test2::x
      IL_0011:  ldloca.s   c
      IL_0013:  ldc.i4.0
      IL_0014:  call       instance void WindowsFormsApplication1.test2::.ctor(int32)
      IL_0019:  nop
      IL_001a:  ret