首页 新闻 会员 周边

关于类字段的初始化。。。

0
悬赏园豆:100 [已解决问题] 解决于 2015-12-26 06:16

比如一个类

class A

{

     int x=1;

     public A()

    {

        x=4;

    }

}

 

问:int x=1;这个赋值操作时在构造函数执行前的啥时候执行的?

龙腾迷的主页 龙腾迷 | 初学一级 | 园豆:7
提问于:2014-06-27 15:34
< >
分享
最佳答案
0

 

 

我需要更正上一位贴图者的一点误解

ldarg.0 是指将图2中Call Stack中索引为0的参数加载到栈中

ldc.i4.1 是指将整数 1 作为int32类型加载到栈中 

stfld     做一个赋值的操作,也就是完成 int x=1;这一个过程

此时 变量x的值就是1了 然后调用

call 指令 注意最后的 .ctor() 这个是引用类型初始化的指令

之后的操作就与前面一至了对x 进行赋值 x=4

从上面的过程来看 x=1 肯定是在构造函数之前就以经完成了初始化,而并不是在构造函数中完成初始化的  

收获园豆:100
Zery | 大侠五级 |园豆:6151 | 2014-06-27 23:26

call 指令 注意最后的 .ctor() 这个是引用类型初始化的指令:这个调用的是基类object的构造函数,而不是这个类本身自己的构造函数。

从上面的过程来看 x=1 肯定是在构造函数之前就以经完成了初始化,而并不是在构造函数中完成初始化的 :所以你这个结论说在构造函数之前的结论不成立吧。

Timetombs | 园豆:3954 (老鸟四级) | 2014-06-28 06:11

@乱舞春秋: 

还好提醒 是基类object的构造函数,你没发现在调用基类的构造方法时 

给x 赋为1 的IL指令就已经执行了吗? 所以最终还是在构造函数前就已经完成了初始化

Zery | 园豆:6151 (大侠五级) | 2014-06-28 13:37

@Zery: 

所以最终还是在构造函数前就已经完成了初始化

如果你这句话中的构造函数是指基类构造函数,那我赞同,但是这个和本类的构造函数根本就是两码事,。

如果你这句话中的构造函数是指本类构造函数,那么怎么就不是在构造函数内执行的x=1了;x=1,调用基类构造函数,x=4,这三个操作都是在本类的构造函数中完成。

Timetombs | 园豆:3954 (老鸟四级) | 2014-06-28 18:32

@乱舞春秋: 现在和构造函数还没扯上关系,可以看图中

stfld int32 StaticDemo.A::X
这里的赋值操作针对的是A类中的x 变量
完了之后才调用Object的构造方法,如果你觉得是在Object基类中初始化的,或者在A类中初始化的,请拿出有力的证明,来证明我是错的,虽然我不能百分百肯定,但是没有理论证明我是错的前,我觉得我想法是正确的,欢迎一起深入探讨这个问题~

Zery | 园豆:6151 (大侠五级) | 2014-06-28 18:43

@Zery: 

c#语言规范

10.11

10.11.1

10.11.2

10.11.3

Timetombs | 园豆:3954 (老鸟四级) | 2014-06-28 19:18

@Zery: 

编译器会把实例变量的初始值设定放到本类的构造函数最开始位置;紧接着会安插对基类构造器的调用,然后再是你写在构造函数中的代码。

Timetombs | 园豆:3954 (老鸟四级) | 2014-06-28 19:22

@乱舞春秋: 呃 终于出结论了,结果是 在构造函数内初始化的,其实我们贴出的IL 图就是A类的构造函数的

只是我过于观注IL 却忘了看这是哪个类的哪个方法了,实际上在new一个A的实例时 会先调用 A的构造完成初始化,而我们贴的IL图 就很明了的体现了初始化这一过程, 再次感谢 你的指正!

Zery | 园豆:6151 (大侠五级) | 2014-06-29 17:45
其他回答(9)
0

new 的时候执行。

Firen | 园豆:5385 (大侠五级) | 2014-06-27 15:37

可以去了解下.NET内存机制。

支持(0) 反对(0) Firen | 园豆:5385 (大侠五级) | 2014-06-27 15:38

@Firen: 好的,好看看! 

支持(0) 反对(0) 龙腾迷 | 园豆:7 (初学一级) | 2014-06-27 16:12
0

对的,类new时,分配堆栈空间时执行!

kimi_gyj | 园豆:192 (初学一级) | 2014-06-27 15:40
0

先执行x=1,再执行x=4,所以结果是x=4

Alex_QY1987 | 园豆:1888 (小虾三级) | 2014-06-27 15:58
0

你看看编译后的代码就明白了

class A

{

     int x;

     public A()

    {

   x=1;//会被安插在这里。

        x=4;

    }

}

Timetombs | 园豆:3954 (老鸟四级) | 2014-06-27 15:59

支持(0) 反对(0) Timetombs | 园豆:3954 (老鸟四级) | 2014-06-27 16:07

如果编译后这这样的,x=1执行完后会立马执行x=4吧。。。

那这种情况

class A

{

      public A()

      {

            PrintFields();

      }

      public virtual void PrintFields(){}

}

class B:A

{

      int x=1;

      int y;

      public B()

      {

            y=-1;

      }

      public override void PrintFields()

      {

            Console.WriteLine("x={0},y={1}",x,y);

      }

}

 

输出就不是x=1,y=0了吧。

支持(0) 反对(0) 龙腾迷 | 园豆:7 (初学一级) | 2014-06-27 16:08

@龙腾迷: 

怎么不是x=1,y=0了,就是啊。

  public B()

      {

           x=1;

           a.PrintFields();//执行的是B类的,x=1,y=0,还未到y=-1。

            y=-1;

      }

支持(0) 反对(0) Timetombs | 园豆:3954 (老鸟四级) | 2014-06-27 16:15

@龙腾迷: 你这是c#语言规范 上的例子吧。

支持(0) 反对(0) Timetombs | 园豆:3954 (老鸟四级) | 2014-06-27 16:28
0

int x=1;对于你的A类,当你使用A a = new A();时,你创建了这个A的对象a,那么它就会立刻为A的所有字段分配存储空间(因为你的A没有继承其他类,不然当创建A对象时,它会先为顶层的父类中继承来的字段分配存储空间,然后层层往下递归最后才对A自身的字段进行内存分配,最高层类字段最先分配,也就是排在前面啦~),因为你这里只有一个x字段,那么是需要分配x的字段空间就好了。

然后就是方法表的创建,这个与你的问题暂时无关,就先不提了。

因为你已经给a对象的x字段分配了存储空间,当执行x=4的时候,x的引用地址中的x就会赋值为4,x是分配在堆栈上的哦,虽然他是值类型,但是它是类型的字段。

希望对你有用

LgV5 | 园豆:221 (菜鸟二级) | 2014-06-27 16:00

可以推荐你看看《你必须知道的.Net2》这本书,解决了我当时学.Net的很多疑惑,也讲的比较易懂,尽管有的知识并没有被覆盖,但是绝对是一本好书

支持(0) 反对(0) LgV5 | 园豆:221 (菜鸟二级) | 2014-06-27 16:20
0

初始化类(全局变量会提前)->执行构造函数。

class A
{
public A()
{
Console.WriteLine(b);
b=5;
}
int b=3;
}

会输出3.

幻天芒 | 园豆:37175 (高人七级) | 2014-06-27 16:05
0

都好厉害

羽商宫 | 园豆:2490 (老鸟四级) | 2014-06-27 16:10
0

如果是新手的话,刚开始研究堆栈的话可能会有点晕,深层的东西先不用去研究,等你掌握的多了好好研究一下也不迟,你的问题答案楼上的已经说的很清楚了

情义之印 | 园豆:15 (初学一级) | 2014-07-03 10:43
0

实例化A类的时候给x分配堆栈的时候执行,建议先看一下基础的,堆栈比较难懂.

晓菜鸟 | 园豆:2594 (老鸟四级) | 2014-07-15 16:56
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册