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

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

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

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

 using System;

 namespace FirstTest
{
class A
{
public static string name = GetName ("Hello World~!"); public static string GetName (string str)
{
Console.WriteLine("初始化静态成员:{0}", str);
return str;
}
} class Program
{
static void Main(string[] args)
{
Console.WriteLine ("输出第一句话");
string temp = A.name;
Console.WriteLine("输出静态成员:{0}", temp);
}
}
}

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

运行结果:

结果出乎意料吧?

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

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

 using System;

 namespace FirstTest
{
class A
{
public static string name = GetName ("Hello World~!"); public static string GetName (string str)
{
Console.WriteLine("初始化静态成员:{0}", str);
return str;
} // 在A类中增加其静态构造方法
static A ()
{
}
} class Program
{
static void Main(string[] args)
{
Console.WriteLine ("输出第一句话");
string temp = A.name;
Console.WriteLine("输出静态成员:{0}", temp);
}
}
}

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

运行结果:

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

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

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

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

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

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

 using System;

 namespace FirstTest
{
class A
{
public static string name = GetName("Hello World~!"); public static string GetName(string str)
{
Console.WriteLine("初始化静态成员:{0}", str);
return str;
} // 在A类中增加其静态构造方法
static A()
{
}
}
class B
{
public static string name = GetName("Learning C#"); public static string GetName(string str)
{
Console.WriteLine("初始化静态成员:{0}", str);
return str;
} // B类中缺少静态构造方法,将由系统自动生成
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("开始执行Main方法");
// 首先引用A类的静态字段
string first = A.name;
// 其次引用B类的静态字段
string second = B.name;
}
}
}

按照观点分析: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类中添加如下两行静态字段,在静态构造函数中添加一行输出语句,进行测试:

 class A
{
public static string front = GetName("前排强势占座!!!!");
public static string name = GetName("Hello World~!");
public static string back = GetName("后排无聊围观...."); public static string GetName(string str)
{
Console.WriteLine("初始化静态成员:{0}", str);
return str;
} // 在静态构造方法增加输出语句
static A()
{
Console.WriteLine("调用静态构造方法");
}
}

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

运行结果:

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

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

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

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

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

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

 using System;

 namespace FourthText
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine ("这是最后一个试验了~\\(≧▽≦)/~啦啦啦");
} static Program()
{
Console.WriteLine ("调用静态构造方法");
}
}
}

运行结果:

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

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

 using System;

 namespace FourthText
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("真的是最后一次试验了Zzz");
} public static string name = GetName("又被骗了(#‵′)凸"); public static string GetName(string str)
{
Console.WriteLine("初始化静态成员:{0}", str);
return str;
}
}
}

运行结果:

【C#】静态构造方法与静态变量的更多相关文章

  1. C#中为什么会出现空静态构造方法的写法

    再过几个小时,就要回家过春节了,今天说些简单点的东西,大家在看C#代码的时候,一定会对这样的写法非常迷茫:在一个类中会出现一个空的静态构造方法.这不是多此一举吗,这样做的目的是什么?今天我就来说说这个 ...

  2. Java类的初始化顺序 (静态变量、静态初始化块、变量、初始...

    很有意思的一篇文章 1.没有继承 静态变量->静态初始化块->变量->变量初始化块->构造方法 2.有继承的情况 父类静态变量->父类静态初始化块->子类静态变量- ...

  3. java静态代码块/静态属性、构造块、构造方法执行、main方法、普通代码块的顺序

    java静态代码块/静态属性.构造块.构造方法执行.main方法.普通代码块的顺序 这也是在笔试中的一个重要的考点,就有一个输出语句让你写出输出的结果. 理论知识: 静态代码块是:属于类的,在类加载时 ...

  4. DotNet中静态成员、静态类、静态构造方法和实例构造方法的区别与联系

    在面向对象的C#程序设计中,关于静态的概念一直是很多人搞不明白的.下面介绍这些带“静态”的名称. 1.静态成员: 定义:静态成员是用static关键字修饰的成员(包括字段属性和方法) 所属:静态成员是 ...

  5. 静态局部变量、静态全局变量、extern全局变量、自动变量 札记

    静态局部变量 静态局部变量. 从称呼上我们可以看出,静态局部变量首先是一个局部变量,因此其只在定义它的函数内有效,冠以静态的头衔后,其生存期就被延长了,不会随着函数的返回而被撤销.我们可以这样来理解: ...

  6. 1、c#中可以有静态构造方法,而java中没有,例如在单例模式中c#可以直接在静态构造中实例化对象,而java不可以

    1.c#中可以有静态构造方法,而java中没有,例如在单例模式中c#可以直接在静态构造中实例化对象,而java不可以

  7. Java 构造器 考虑用静态构造方法代替构造器

    类可以提供一个公有的静态工厂方法,它是一个返回类的实例的静态方法.静态工厂方法与设计模式中的工厂方法模式不同. 优势: 静态工厂方法与构造器不同的第一大优势在于,它们有名称.一个类只能有一个带有指定签 ...

  8. C# 静态构造函数,静态变量执行顺序(精华版)(规正版)

    一.成员初始化整体顺序 1.成员赋值初始化先于构造函数: 2.成员赋值初始先从子类再到基类: 3.构造函数初始化先从基类再到子类: 4.静态成员初始化优先于实例成员初始化: 二.对类型静态成员构造的大 ...

  9. Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】

    郝萌主倾心贡献,尊重作者的劳动成果.请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 构造方法 ...

随机推荐

  1. 【NOI2001】方程的解数 题解(dfs+哈希)

    题目描述 已知一个方程 k1*x1^p1+k2*x2^p2……+kn*xn^pn=0. 求解的个数.其中1<=x<=150,1<=p<=6; 答案在int范围内 输入格式 第一 ...

  2. SpringMVC 集成 JWT验证方式

    JWT官网: https://jwt.io/ 这里以java的ssm框架为例,集成jwt. 1.pom.xml 导入jwt的包 <!-- jwt --> <dependency> ...

  3. 微信公众号添加zip

    微信公众号添加zip的教程 我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件. 以下是公众号添加 ...

  4. [leetcode/lintcode 题解] 前序遍历和中序遍历树构造二叉树

    [题目描述] 根据前序遍历和中序遍历树构造二叉树. 在线评测地址: https://www.jiuzhang.com/solution/construct-binary-tree-from-preor ...

  5. 2020-04-07:说出Servlet的生命周期,并说出Servlet和CGI的区别。

    Servlet的生命周期分为5个阶段:实例化:Servlet容器创建Servlet类的实例.初始化:该容器调用init()方法,通常会申请资源.服务:由容器调用service()方法,(也就是doGe ...

  6. 双向BFS和启发式搜索的应用

    题目链接 P5507 机关 题意简述   有12个旋钮,每个旋钮开始时处于状态 \(1\) ~ \(4\) ,每次操作可以往规定方向转动一个旋钮 (\(1\Rightarrow2\Rightarrow ...

  7. 金题大战Vol.0 A、凉宫春日的叹息

    金题大战Vol.0 A.凉宫春日的叹息 题目描述 给定一个数组,将其所有子区间的和从小到大排序,求第 \(k\) 小的是多少. 输入格式 第一行两个数\(n\),$ k\(,表示数组的长度和\)k$: ...

  8. STL函数库的应用第二弹——快排sort函数与结构体关键字排序

    时隔20多天,本蒟蒻终于记起了他的博客园密码!!! 废话不多说,今天主题:STL快排函数sort()与结构体关键字排序 Part 1:引入和导语 首先,我们需要知道,algorithm库里有一些奇怪的 ...

  9. C++ 不具有继承关系的类之间的显式,隐式转换 2013-07-11 15:41

    好久没有写blog了,今天在学习c#的时候看到某一章节 讲类的隐式与显式转换.特此留笔,以供后续参考之用. 关于显式,隐式转换有些争论,说什么不建议隐式转换.但是个人认为非必要,如果有良好的基础书写基 ...

  10. JavaScript学习系列博客_7_JavaScript中的逻辑运算符、三元运算符

    逻辑运算符 ! 非 - 非运算可以对一个布尔值进行取反,true变false false边true - 当对非布尔值使用!时,会先将其转换为布尔值然后再取反 - 我们可以利用 !! 来将其他的数据类型 ...