这段程序代码搞不清楚了

时间:2021-07-06 16:22:10
这是一道笔试题

namespace ConsoleApplication1
{
    class A
    {
        public static int x;
        static A()
        {
            x = B.y + 1;
        }
    }


    class B 
    {
        public static int y = A.x + 1;

    }
        



    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("x={0},y={1}", A.x, B.y);
            Console.ReadKey();
        }
    }
}


经过调试发现首先执行public static int y = A.x + 1; 结果是y = 0;然后执行x = B.y + 1;结果是x=1,最后又回到public static int y = A.x + 1;执行结果是y=2.

25 个解决方案

#1


没有赋值的时候x y都是0,先执行A.x,x=0+1=1, 然后执行B.y=1+1=2

#2


Console.WriteLine("x={0},y={1}", A.x, B.y);
一开始先调用A的构造函数,同时变量x也出来了,默认值是0,然后函数里面用到了类B,所以掉用了B的构造函数,然后使用到了类A的静态变量x,这个变量之前已经被创建了,值是0,所以这时候y的值是0+1=1,接着回头把1返回给类A使用,最后x的值就变为1+1=2了。

#3


你要搞清初始化的先后顺序就 OK 了

1. 类的静态变量定义时的赋值语句
2. 类的静态构造函数
3. 类的实例变量定义时的赋值语句
4. 类的实例构造函数

在这里,没有创建对象,所以 3、4 忽略。
1. 程序按照顺序初始化 A、B 的静态变量。
   这里:public static int y = A.x + 1; A.x 这个时候是 0!
   然后初始化完,变成 1;所以 y = 1
2. 接着初始化 A 的构造函数, 静态构造函数是在第一次调用静态变量的时候初始化的。所以,在做:
Console.WriteLine("x={0},y={1}", A.x, B.y); 
这句话的时候触发了静态构造函数的调用,使得 x = 2

#4


A.x, B.y

当静态构造函数给X赋值的时候 调用B的静态构造函数这个时候 x=0 得出y=0+1  y=1

然后将y的值代入 此时x=2

#5


1楼正解

#6


调试时,一开始并不是调用A的构造函数,而是直接运行public static int y = A.x + 1;然后再调用A的构造函数.也许这是编译器做的优化.

#7


2,3,4楼都答错了,这段代码最后输出的结果是:x=1,y=2

#8


这段代码挺高深的...先执行的是B类,然后A类,再次B类,最后main方法...

不信你们可以调试一下,一开始就没有进入main方法

#9


分别在 x = B.y + 1;public static int y = A.x + 1;和      static void Main(string[] args)行设置断点,然后按F5调试程序,就会发现程序首先执行的是public static int y = A.x + 1;这一行.这行代码的第一个操作数是A.x,所以跳到x = B.y + 1;去计算x的值,在这一行中B.y是0,得出x=1,然后回到public static int y = A.x + 1;这一行继续执行,计算出y=2.最后回到主程序的入口处,即static void Main(string[] args)行处,显示出结果x=1,y=2.

#10


学员飘过!

#11


引用 1 楼 buptwm 的回复:
没有赋值的时候x y都是0,先执行A.x,x=0+1=1, 然后执行B.y=1+1=2

a.x时候x=b.y+1,因为b没有构造函数所以y=0 ,得到a.x=1
b.y调用a的默认构造函数

#12


应该是b.y调用a的构造函数 y=a.x+1=2

#13


引用 11 楼 ytmf007 的回复:
引用 1 楼 buptwm 的回复:

a.x时候x=b.y+1,因为b没有构造函数所以y=0 ,得到a.x=1

B虽然没有静态构造函数,但是它有静态字段的初始化值,而初始化的执行是优先于构造函数的.

#14


静态构造,会实例类的时候就执行,静态参数也一样

#15


 class A
    {
        public static int x;
        static A()//这是啥
        {
            x = B.y + 1;
        }
    }

}

#16


通过上面的例子可以得出这样一个结论:如果Main()中的一段代码引用了一个类的公共静态字段,而这个类又没有显式的静态构造函数,此时将先执行该字段的初始化赋值操作,然后再执行Main()函数.

#17


引用 15 楼 xiaoshenyi2 的回复:
class A
  {
  public static int x;
  static A()//这是啥
  {
  x = B.y + 1;
  }
  }

}

这是静态构造函数.

#18


该回复于2012-03-07 16:49:41被版主删除

#19


引用 16 楼 schinar 的回复:
通过上面的例子可以得出这样一个结论:如果Main()中的一段代码引用了一个类的公共静态字段,而这个类又没有显式的静态构造函数,此时将先执行该字段的初始化赋值操作,然后再执行Main()函数.


貌似你说的有点道理哦!!!

#20


其实,看下生成的il代码就知道了
class B 
{
   public static int y = A.x + 1;
}
的il代码里,把=A.x + 1放到static的构造函数里了

.method private hidebysig specialname rtspecialname static 
        void  .cctor() cil managed
{
  // 代码大小       13 (0xd)
  .maxstack  8
  IL_0000:  ldsfld     int32 ConsoleApplication1.A::x
  IL_0005:  ldc.i4.1
  IL_0006:  add
  IL_0007:  stsfld     int32 ConsoleApplication1.B::y
  IL_000c:  ret
} // end of method B::.cctor


而A的构造函数是:
.method private hidebysig specialname rtspecialname static 
        void  .cctor() cil managed
{
  // 代码大小       14 (0xe)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldsfld     int32 ConsoleApplication1.B::y
  IL_0006:  ldc.i4.1
  IL_0007:  add
  IL_0008:  stsfld     int32 ConsoleApplication1.A::x
  IL_000d:  ret
} // end of method A::.cctor

#21


这样,等效的C#代码是:
namespace ConsoleApplication1
{
    class A
    {
        public static int x;
        static A()
        {
            x = B.y + 1;
        }
    }


    class B
    {
        public static int y;
        static B()
        {
            y = A.x + 1;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("x={0},y={1}", A.x, B.y);
            Console.ReadKey();
        }
    }

访问A.x时,A()被执行,执行到x = B.y + 1时,B()被执行,此时x为0,所以y=1,然后x=1+1
最后结果是x2 y1

#22


不对,好像解释错了,代码不等效,再研究下

#23


静态构造函数是C#的一个新特性,其实好像很少用到。不过当我们想初始化一些静态变量的时候就需要用到它了。这个构造函数是属于类的,而不是属于哪里实例的,就是说这个构造函数只会被执行一次。也就是在创建第一个实例或引用任何静态成员之前,由.NET自动调用。

#24


在使用静态构造函数的时候应该注意几点:

  1、静态构造函数既没有访问修饰符,也没有参数。因为是.NET调用的,所以像public和private等修饰符就没有意义了。
  
  2、是在创建第一个类实例或任何静态成员被引用时,.NET将自动调用静态构造函数来初始化类,也就是说我们无法直接调用静态构造函数,也就无法控制什么时候执行静态构造函数了。

  3、一个类只能有一个静态构造函数。

  4、无参数的构造函数可以与静态构造函数共存。尽管参数列表相同,但一个属于类,一个属于实例,所以不会冲突。

  5、最多只运行一次。

  6、静态构造函数不可以被继承。

  7、如果没有写静态构造函数,而类中包含带有初始值设定的静态成员,那么编译器会自动生成默认的静态构造函数。

#25


再看了下il代码,发现class B被标记了.class private auto ansi beforefieldinit
说明B的构造函数要优先执行

那结果为x=1,y=2就可以理解了
参考beforefieldinit的解释:
http://www.cnblogs.com/foundation/archive/2008/11/06/1327927.html

可惜不能编辑前面的回复

#1


没有赋值的时候x y都是0,先执行A.x,x=0+1=1, 然后执行B.y=1+1=2

#2


Console.WriteLine("x={0},y={1}", A.x, B.y);
一开始先调用A的构造函数,同时变量x也出来了,默认值是0,然后函数里面用到了类B,所以掉用了B的构造函数,然后使用到了类A的静态变量x,这个变量之前已经被创建了,值是0,所以这时候y的值是0+1=1,接着回头把1返回给类A使用,最后x的值就变为1+1=2了。

#3


你要搞清初始化的先后顺序就 OK 了

1. 类的静态变量定义时的赋值语句
2. 类的静态构造函数
3. 类的实例变量定义时的赋值语句
4. 类的实例构造函数

在这里,没有创建对象,所以 3、4 忽略。
1. 程序按照顺序初始化 A、B 的静态变量。
   这里:public static int y = A.x + 1; A.x 这个时候是 0!
   然后初始化完,变成 1;所以 y = 1
2. 接着初始化 A 的构造函数, 静态构造函数是在第一次调用静态变量的时候初始化的。所以,在做:
Console.WriteLine("x={0},y={1}", A.x, B.y); 
这句话的时候触发了静态构造函数的调用,使得 x = 2

#4


A.x, B.y

当静态构造函数给X赋值的时候 调用B的静态构造函数这个时候 x=0 得出y=0+1  y=1

然后将y的值代入 此时x=2

#5


1楼正解

#6


调试时,一开始并不是调用A的构造函数,而是直接运行public static int y = A.x + 1;然后再调用A的构造函数.也许这是编译器做的优化.

#7


2,3,4楼都答错了,这段代码最后输出的结果是:x=1,y=2

#8


这段代码挺高深的...先执行的是B类,然后A类,再次B类,最后main方法...

不信你们可以调试一下,一开始就没有进入main方法

#9


分别在 x = B.y + 1;public static int y = A.x + 1;和      static void Main(string[] args)行设置断点,然后按F5调试程序,就会发现程序首先执行的是public static int y = A.x + 1;这一行.这行代码的第一个操作数是A.x,所以跳到x = B.y + 1;去计算x的值,在这一行中B.y是0,得出x=1,然后回到public static int y = A.x + 1;这一行继续执行,计算出y=2.最后回到主程序的入口处,即static void Main(string[] args)行处,显示出结果x=1,y=2.

#10


学员飘过!

#11


引用 1 楼 buptwm 的回复:
没有赋值的时候x y都是0,先执行A.x,x=0+1=1, 然后执行B.y=1+1=2

a.x时候x=b.y+1,因为b没有构造函数所以y=0 ,得到a.x=1
b.y调用a的默认构造函数

#12


应该是b.y调用a的构造函数 y=a.x+1=2

#13


引用 11 楼 ytmf007 的回复:
引用 1 楼 buptwm 的回复:

a.x时候x=b.y+1,因为b没有构造函数所以y=0 ,得到a.x=1

B虽然没有静态构造函数,但是它有静态字段的初始化值,而初始化的执行是优先于构造函数的.

#14


静态构造,会实例类的时候就执行,静态参数也一样

#15


 class A
    {
        public static int x;
        static A()//这是啥
        {
            x = B.y + 1;
        }
    }

}

#16


通过上面的例子可以得出这样一个结论:如果Main()中的一段代码引用了一个类的公共静态字段,而这个类又没有显式的静态构造函数,此时将先执行该字段的初始化赋值操作,然后再执行Main()函数.

#17


引用 15 楼 xiaoshenyi2 的回复:
class A
  {
  public static int x;
  static A()//这是啥
  {
  x = B.y + 1;
  }
  }

}

这是静态构造函数.

#18


该回复于2012-03-07 16:49:41被版主删除

#19


引用 16 楼 schinar 的回复:
通过上面的例子可以得出这样一个结论:如果Main()中的一段代码引用了一个类的公共静态字段,而这个类又没有显式的静态构造函数,此时将先执行该字段的初始化赋值操作,然后再执行Main()函数.


貌似你说的有点道理哦!!!

#20


其实,看下生成的il代码就知道了
class B 
{
   public static int y = A.x + 1;
}
的il代码里,把=A.x + 1放到static的构造函数里了

.method private hidebysig specialname rtspecialname static 
        void  .cctor() cil managed
{
  // 代码大小       13 (0xd)
  .maxstack  8
  IL_0000:  ldsfld     int32 ConsoleApplication1.A::x
  IL_0005:  ldc.i4.1
  IL_0006:  add
  IL_0007:  stsfld     int32 ConsoleApplication1.B::y
  IL_000c:  ret
} // end of method B::.cctor


而A的构造函数是:
.method private hidebysig specialname rtspecialname static 
        void  .cctor() cil managed
{
  // 代码大小       14 (0xe)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldsfld     int32 ConsoleApplication1.B::y
  IL_0006:  ldc.i4.1
  IL_0007:  add
  IL_0008:  stsfld     int32 ConsoleApplication1.A::x
  IL_000d:  ret
} // end of method A::.cctor

#21


这样,等效的C#代码是:
namespace ConsoleApplication1
{
    class A
    {
        public static int x;
        static A()
        {
            x = B.y + 1;
        }
    }


    class B
    {
        public static int y;
        static B()
        {
            y = A.x + 1;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("x={0},y={1}", A.x, B.y);
            Console.ReadKey();
        }
    }

访问A.x时,A()被执行,执行到x = B.y + 1时,B()被执行,此时x为0,所以y=1,然后x=1+1
最后结果是x2 y1

#22


不对,好像解释错了,代码不等效,再研究下

#23


静态构造函数是C#的一个新特性,其实好像很少用到。不过当我们想初始化一些静态变量的时候就需要用到它了。这个构造函数是属于类的,而不是属于哪里实例的,就是说这个构造函数只会被执行一次。也就是在创建第一个实例或引用任何静态成员之前,由.NET自动调用。

#24


在使用静态构造函数的时候应该注意几点:

  1、静态构造函数既没有访问修饰符,也没有参数。因为是.NET调用的,所以像public和private等修饰符就没有意义了。
  
  2、是在创建第一个类实例或任何静态成员被引用时,.NET将自动调用静态构造函数来初始化类,也就是说我们无法直接调用静态构造函数,也就无法控制什么时候执行静态构造函数了。

  3、一个类只能有一个静态构造函数。

  4、无参数的构造函数可以与静态构造函数共存。尽管参数列表相同,但一个属于类,一个属于实例,所以不会冲突。

  5、最多只运行一次。

  6、静态构造函数不可以被继承。

  7、如果没有写静态构造函数,而类中包含带有初始值设定的静态成员,那么编译器会自动生成默认的静态构造函数。

#25


再看了下il代码,发现class B被标记了.class private auto ansi beforefieldinit
说明B的构造函数要优先执行

那结果为x=1,y=2就可以理解了
参考beforefieldinit的解释:
http://www.cnblogs.com/foundation/archive/2008/11/06/1327927.html

可惜不能编辑前面的回复