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了。
一开始先调用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
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
当静态构造函数给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方法
不信你们可以调试一下,一开始就没有进入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
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
B虽然没有静态构造函数,但是它有静态字段的初始化值,而初始化的执行是优先于构造函数的.
#14
静态构造,会实例类的时候就执行,静态参数也一样
#15
class A
{
public static int x;
static A()//这是啥
{
x = B.y + 1;
}
}
}
{
public static int x;
static A()//这是啥
{
x = B.y + 1;
}
}
}
#16
通过上面的例子可以得出这样一个结论:如果Main()中的一段代码引用了一个类的公共静态字段,而这个类又没有显式的静态构造函数,此时将先执行该字段的初始化赋值操作,然后再执行Main()函数.
#17
这是静态构造函数.
#18
#19
貌似你说的有点道理哦!!!
#20
其实,看下生成的il代码就知道了
class B
{
public static int y = A.x + 1;
}
的il代码里,把=A.x + 1放到static的构造函数里了
而A的构造函数是:
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#代码是:
访问A.x时,A()被执行,执行到x = B.y + 1时,B()被执行,此时x为0,所以y=1,然后x=1+1
最后结果是x2 y1
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、如果没有写静态构造函数,而类中包含带有初始值设定的静态成员,那么编译器会自动生成默认的静态构造函数。
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
可惜不能编辑前面的回复
说明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了。
一开始先调用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
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
当静态构造函数给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方法
不信你们可以调试一下,一开始就没有进入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
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
B虽然没有静态构造函数,但是它有静态字段的初始化值,而初始化的执行是优先于构造函数的.
#14
静态构造,会实例类的时候就执行,静态参数也一样
#15
class A
{
public static int x;
static A()//这是啥
{
x = B.y + 1;
}
}
}
{
public static int x;
static A()//这是啥
{
x = B.y + 1;
}
}
}
#16
通过上面的例子可以得出这样一个结论:如果Main()中的一段代码引用了一个类的公共静态字段,而这个类又没有显式的静态构造函数,此时将先执行该字段的初始化赋值操作,然后再执行Main()函数.
#17
这是静态构造函数.
#18
#19
貌似你说的有点道理哦!!!
#20
其实,看下生成的il代码就知道了
class B
{
public static int y = A.x + 1;
}
的il代码里,把=A.x + 1放到static的构造函数里了
而A的构造函数是:
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#代码是:
访问A.x时,A()被执行,执行到x = B.y + 1时,B()被执行,此时x为0,所以y=1,然后x=1+1
最后结果是x2 y1
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、如果没有写静态构造函数,而类中包含带有初始值设定的静态成员,那么编译器会自动生成默认的静态构造函数。
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
可惜不能编辑前面的回复
说明B的构造函数要优先执行
那结果为x=1,y=2就可以理解了
参考beforefieldinit的解释:
http://www.cnblogs.com/foundation/archive/2008/11/06/1327927.html
可惜不能编辑前面的回复