【C#】静态构造方法与静态变量

扯下闲篇先,本来今天预计整理下委托、事件、Lamada的笔记,然后再把单例模式的懒汉、饿汉模式看完。

在看到懒汉的双重加锁设计时,向同桌贩卖了下该设计的优点,结果反被同桌的一个问题难倒了~!

 

一. 有无静态构造方法,运行结果大不同

问题:请问下面代码的运行结果是什么?

 1 using System;
 2 
 3 namespace FirstTest
 4 {
 5     class A
 6     {
 7         public static string name = GetName ("Hello World~!");
 8 
 9         public static string GetName (string str)
10         {
11             Console.WriteLine("初始化静态成员:{0}", str);
12             return str;
13         }
14     }
15 
16     class Program
17     {
18         static void Main(string[] args)
19         {
20             Console.WriteLine ("输出第一句话");
21             string temp = A.name;
22             Console.WriteLine("输出静态成员:{0}", temp);
23         }
24     }
25 }

一开始,我认为是:1)输出第一句话 2)初始化静态成员 3)输出静态成员

运行结果:

结果出乎意料吧?

为什么静态成员的初始化反而先于第一句话执行呢??

正在我百思不得其解的时候,同桌在原代码的基础上稍加改动,又发给了我:

 1 using System;
 2 
 3 namespace FirstTest
 4 {
 5     class A
 6     {
 7         public static string name = GetName ("Hello World~!");
 8 
 9         public static string GetName (string str)
10         {
11             Console.WriteLine("初始化静态成员:{0}", str);
12             return str;
13         }
14 
15         // 在A类中增加其静态构造方法
16         static A ()
17         {
18         }
19     }
20 
21     class Program
22     {
23         static void Main(string[] args)
24         {
25             Console.WriteLine ("输出第一句话");
26             string temp = A.name;
27             Console.WriteLine("输出静态成员:{0}", temp);
28         }
29     }
30 }

这一次,运行结果和我刚刚预期的结果反而一致了。

运行结果:

为什么A类中有无静态构造方法,会对运行结果造成如此影响?

在对度娘上的博客进行各种遍历搜索查询之后,终于捋清了如下思路

  1. 前后两段代码的异同点,仅局限于A类中有无静态构造方法。在缺少静态构造方法的情况下(即第一种情况),运行结果“异常”(不符合预期结果)。
  2. 在缺少静态构造方法的情况下,程序会自动生成默认静态构造方法

由以上两点推测,较为认同如下观点

  • 编译器在编译的时候,会事先分析Main方法中所需要的静态字段
  • 如果这些静态字段所在的类有静态构造函数,则只有在初次引用该字段(或初次实例化类)的时候才进行初始化
  • 否则,在调用Main方法前,自动生成静态构造方法,对静态字段进行初始化

 继续码代码:增加一个class B,在Main方法中分别调用A、B的静态字段,印证观点

 1 using System;
 2 
 3 namespace FirstTest
 4 {
 5     class A
 6     {
 7         public static string name = GetName("Hello World~!");
 8 
 9         public static string GetName(string str)
10         {
11             Console.WriteLine("初始化静态成员:{0}", str);
12             return str;
13         }
14 
15         // 在A类中增加其静态构造方法
16         static A()
17         {
18         }
19     }
20     class B
21     {
22         public static string name = GetName("Learning C#");
23 
24         public static string GetName(string str)
25         {
26             Console.WriteLine("初始化静态成员:{0}", str);
27             return str;
28         }
29 
30         // B类中缺少静态构造方法,将由系统自动生成
31     }
32     class Program
33     {
34         static void Main(string[] args)
35         {
36             Console.WriteLine("开始执行Main方法");
37             // 首先引用A类的静态字段
38             string first  = A.name; 
39             // 其次引用B类的静态字段
40             string second = B.name;
41         }
42     }
43 }

按照观点分析:1)初始化静态成员:Learning C# 2)开始执行Main方法 3)初始化执行静态成员:Hello World~!

运行结果:

与观点分析的预期相符,结题。

参考博文:

《浅谈静态字段与静态构造函数之间的初始化关系以及执行顺序》

作者:Rain

http://www.cnblogs.com/cpcpc/archive/2010/04/16/2123135.html

 

二. 静态构造方法与静态字段的执行顺序

在查阅上个问题的过程中,发现在MSDN上对静态构造方法的描述中有如下一条内容:

如果类包含任何带有初始值设定项的静态字段,则在执行该类的静态构造函数时,先要按照文本顺序执行那些初始值设定项

观点主要阐述了以下3点:

  • 执行静态构造方法时,先对静态字段进行初始化,然后再调用静态构造方法里面的内容
  • 对静态字段进行初始化时,按照静态字段声明的依次顺序进行
  • 若静态字段含有初始值含有初始值设定项,则使用设定项。否则对其使用默认值,值类型的默认值为0(其中布尔类型为false),引用类型的默认值为null。

本着打破砂锅问到底的精神,仅在A类中添加如下两行静态字段,在静态构造函数中添加一行输出语句,进行测试:

 1 class A
 2 {
 3     public static string front = GetName("前排强势占座!!!!");
 4     public static string name = GetName("Hello World~!");
 5     public static string back = GetName("后排无聊围观....");
 6 
 7     public static string GetName(string str)
 8     {
 9         Console.WriteLine("初始化静态成员:{0}", str);
10         return str;
11     }
12 
13     // 在静态构造方法增加输出语句
14     static A()
15     {
16         Console.WriteLine("调用静态构造方法");
17     }
18 }

按照MSDN的观点:1)初始化静态成员:Learning C# 2)开始执行Main方法 3)初始化执行静态成员:前排强势占座!!!! 4)初始化执行静态成员:Hello World~! 5)初始化执行静态成员:后排无聊围观.... 6)调用静态构造方法

运行结果:

 

与观点分析的预期相符,新姿势Get√

另外,根据MSDN中的静态构造函数设计中的描述,CLR可以优化对静态字段进行初始值设定项的代码。

 

三. 静态构造方法与Main方法的执行顺序

同样的,在MSDN中发现如下观点:

如果类中包含用来开始执行的 Main 方法,则该类的静态构造函数将在调用 Main 方法之前执行。

重写一份代码(含有静态构造方法),再次实验下:

 1 using System;
 2 
 3 namespace FourthText
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Console.WriteLine ("这是最后一个试验了~\\(≧▽≦)/~啦啦啦");
10         }
11 
12         static Program()
13         {
14             Console.WriteLine ("调用静态构造方法");
15         }
16     }
17 }

运行结果:

与观点分析的预期相符,新姿势Get√

啊啊啊啊O(≧口≦)O,还不能结题~!结合第一、二条知识,再次测试下没有静态构造方法下的情况吧:

 1 using System;
 2 
 3 namespace FourthText
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Console.WriteLine("真的是最后一次试验了Zzz");
10         }
11 
12         public static string name = GetName("又被骗了(#‵′)凸");
13 
14         public static string GetName(string str)
15         {
16             Console.WriteLine("初始化静态成员:{0}", str);
17             return str;
18         }
19     }
20 }

运行结果:

 

转载于:https://www.cnblogs.com/muxiaomo/p/4483730.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值