上篇 是基本语法基础下的执行顺序,包括继承这个维度下的执行顺序,我们可以依照的规律顺下来,下面我们看下一些摸不到头脑的情况

我们实验 一个 类中的方法 去调用另一个非继承类的情况,  我们主要看下  静态构造函数 和没有静态构造函数执行顺序上的差别

class Program
{
static void Main(string[] args)
{ //执行顺序5
var de = new People("2"); //执行顺序6
People.Instance.OutDemo(); //执行顺序8 Console.ReadKey(); //执行顺序10
} } public class People
{
public void OutDemo()
{ //执行顺序9
Console.WriteLine($"HaHa");
} public static readonly People Instance = new People(); //执行顺序1 public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序4 private People()
{ //执行顺序2
Console.WriteLine(3); //执行顺序3
} public People(string ss)
{ //执行顺序7 }
}

 

执行顺序 大致是上面十个步骤, 是不是感觉有点蒙蔽了,首先刚开始就没进Main函数,跳到 People下面了,好吧,我们暂且给自己一个说服自己的理由,如果方法中有直接调另一个类的静态成员的,先去走到另一个类中去初始化去.
ok, 接下来 执行顺序1 中赋值的时候 调的 new People(),然后到 执行顺序2 里面, 而另一个静态的 执行顺序4 在执行顺序3走完 随后 ,这个也可以理解,谁让执行顺序2 人家 赋值的时候 调的构造函数呢,然后执行顺序4走完 ok,没有静态的了,调回到原 Program里的main方法了,这个和上篇讲的静态走完再走非静态的不一样,这个也可以理解,谁让两个类不是继承的呢,到Program的Main后 继续 5 、6、7、 8、9、10,这个顺序没有异议。
ok,我们似乎给了自己一个完美的解释。先别高兴的太早,接下来,我们一步步走起,我们再做一件事情:
我们给program定义一个静态构造函数。然后再看下顺序会是什么样的:

 class Program
{
static Program()
{ //然后执行 } static void Main(string[] args)
{ var de = new People("2");
People.Instance.OutDemo(); Console.ReadKey(); //执行顺序10
} public static string sdds = "sdds"; //最先执行
}

我们加了个静态字段,又加了个静态构造函数, 整个顺序: 最先执行 ,然后执行 ,执行顺序1,执行顺序2,......

没有问题,和上片的知识体系相符,没啥惊喜

既然Program下没什么东东,我们就整下 People类吧,我们也给People类加个静态构造函数,现在看看:

class Program
{
static Program()
{ //然后执行 } static void Main(string[] args)
{ 执行顺序1 var de = new People("2"); 执行顺序2
People.Instance.OutDemo(); //执行顺序8 Console.ReadKey();
} public static string sdds = "sdds"; //最先执行
} public class People
{ static People()
{ //执行顺序7 } public void OutDemo()
{ //执行顺序9
Console.WriteLine($"HaHa");
} public static readonly People Instance = new People(); //执行顺序3 public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序6 private People()
{ //执行顺序4
Console.WriteLine(3); //执行顺序5
} public People(string ss)
{ //执行顺序7 }
}

眼尖的你发现 给People加了个静态构造函数,现在顺序变成了: 最先执行,然后执行,执行顺序1,执行顺序2,执行顺序3,....,发现 Program静态走完后,走进去Main方法了,不是先进People了。

啊,匪夷所思,那么没关系,我们自解惑的思想继续改造。我们在先前的一个思想上再加个情况,如果一个类A中去调用另一个类B的静态成员,如果类B有定义了静态的构造函数,那么我们就按顺序走,不会先预先跑到B中初始化B的静态相关的。只到代码碰到B的地方,再去B中走静态相关的部分。

ok,好像我们的理论又成熟了一步,我们在看看,还有什么意外不

又来了一个新点子去验证下,如果我们在People中,在初始化静态成员的时候,再去调第三个类的静态成员呢:

.....

 public static readonly People Instance = new People();        //执行顺序3

  public static Action Inssstance = () => { Console.WriteLine("11"); };      //执行顺序7

 private People()
{ //执行顺序5
var d= Money.Count //执行顺序6
Console.WriteLine(3);
} ........ public class Money
{
public static int Count= "4"; //执行顺序4
} ......

我们发现相关顺序仔细捋下来好像没有什么意外, 执行顺序 3 后 会去调 new People 调这个方法的时候,我们先有个预判断,发现这个方法里面有个调用第三个类Money的静态成员,而第Money又没有定义静态构造函数,嗯,符合跳转的条件 ,然后 到了 执行顺序4 , 然后是执行顺序5 ,然后是执行顺序6 ,执行顺序7

接下来,迫不及待的给Money加个静态构造函数

.....

   static People()
{ //执行顺序10 } public static readonly People Instance = new People(); //执行顺序3 public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序9 private People()
{ //执行顺序4
var d= Money.Count //执行顺序5
Console.WriteLine(3); //执行顺序8
} ........ public class Money
{
static Money()
{ //执行顺序7 } public static int Count= "4"; //执行顺序6
} ......

依然符合。结论依然牢固

还要继续玩吗,继续新的怀疑

如果我们把不被别的地方调的静态成员变成私有的呢,会不会影响顺序了,这个我这里就不列了,答案是:不会

继续,总觉的还有没有挖掘的东西需要一探究竟

我们突然发现,上面我们调的都是另一个类的静态字段,如果是调的另一个类的静态方法呢,会不会也是这个规律呢

改造起来

class Program
{
static Program()
{ //然后执行 } static void Main(string[] args)
{ 执行顺序1 // var de = new People("2");
//People.Instance.OutDemo();
People.xixi(); //执行顺序2 Console.ReadKey(); //执行顺序8
} public static string sdds = "sdds"; //最先执行
} public class People
{ public static string xixi()
{ //执行顺序7
return "xixi";
} public void OutDemo()
{
Console.WriteLine($"HaHa");
} public static readonly People Instance = new People(); //执行顺序3 public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序6 private People()
{ //执行顺序4
Console.WriteLine(3); //执行顺序5
} public People(string ss)
{ }
}

简单测试发现,好像直接调另一个类的静态方法没有符合上面的规律,而是符合常规的规律,不过People加不加静态构造函数,都不会有我们发现的”预先跳转“,它和调用另一个类的静态字段不一样,就调用另一类的静态字段有这个特殊性预先跳转,具体大家可以测试下

如果我们在调用的时候再加上调用People那个静态字段,那效应就会出来了:

.......

 static void Main(string[] args)
{ People.xixi();
People.Instance.OutDemo(); //有这个 就会先判断People有没有静态构造函数,来决定是否在进main方法前先 预先跳转 Console.ReadKey();
} ......

如果对调用层做个包装呢


....
static void Main(string[] args)
{ //执行顺序1
dtas(); //执行顺序2
// Console.WriteLine(People.Instance.OutDemo());
Console.ReadKey();
} public static void dtas()
{ //执行顺序4
People.Instance.OutDemo();
} ....... //假设People没有静态构造函数 ...... //public static readonly People Instance = new People(); //执行顺序3 ....

结果也符合,进main方法了,在进dtas()方法时进行了预先判断,注意,方法的包一层,我注释的:Console.WriteLine(People.Instance.OutDemo());其实和 datas()是一个效果,都是包了一层,不要反应不过来哟

然后,我们对People的静态字段再改下

......

   static void Main(string[] args)
{ 执行顺序2 People.Instance().OutDemo(); 执行顺序3 Console.ReadKey(); //执行顺序7
} ....... //假设People没有静态构造函数 ...... //public static readonly People Instance = new People();
//换成下面这中
public static readonly Func Instance = () => { 执行顺序1
return new People(); 执行顺序4
}; public void OutDemo()
{ 执行顺序5
Console.WriteLine($"HaHa"); 执行顺序6
} .......

我们发现这个调用静态字段如果用委托的方式,会到 Instance这个没错,但是 字段的赋值部分(return new People())就在后期真正调的时候执行了,这个大家注意下这点

在最后给大家一个层次多点的例子,或许你们会吐槽哪有这么写代码的,现实情况下也不这么调啊,一点都不实际,其实还真有场景有可能这么调的,这只是一个映射现实代码的一个 简单的demo原型而已。你们能捋通下面的了吗?再试着给Middle加个静态构造函数呢?你们可以试试,我就不展示了

 class Class1
{ static void Main(string[] args)
{ //执行顺序 6
var obj = People.Instance; //执行顺序 7 Console.Read(); //执行顺序 8
}
} public class People
{
public static readonly ZIS2 Instance = Middle.mid; //执行顺序 4 public static string dsds = "sdd"; //执行顺序 5
} public class Middle
{
public static ZIS2 mid = ZIS2.Instance; //执行顺序 3 } public class ZIS2
{
public static ZIS2 Instance = new ZIS2(); //执行顺序 1 private ZIS2()
{ //执行顺序 2 }
}

到现在为止,我们就暂且告一段落了,当然最后声明下,上面的这些测试都是一次调用的情况,我们想大家应该知道。其实,上面说了那么一大堆,这个现象的原理是什么,编译器编译后他们都有什么不同呢

来看下 下片的介绍:关于 BeforeFieldInit 的东西 : 点我

C# 静态构造函数,静态变量执行顺序(升华版)的更多相关文章

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

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

  2. java静态初始化块的执行顺序

    先来观察下面的代码 package trr; class Root { static{ System.out.println("Root的静态初始化块"); } { System. ...

  3. java中静态初始化块的执行顺序

    在java中,其应该是先于所有的方法执行. 下面是测试代码: public class Test1 { static{ System.out.println("执行静态初始化块test1.. ...

  4. 由阿里巴巴一道笔试题看Java静态代码块、静态函数、动态代码块、构造函数等的执行顺序

    一.阿里巴巴笔试题: public class Test { public static int k = 0; public static Test t1 = new Test("t1&qu ...

  5. java中的静态代码块等执行顺序

    http://www.cnblogs.com/naruto469/p/3608459.html public class Print { 2 3 public Print(String s){ 4 S ...

  6. 1.7Oob封装 继承 访问修饰符 静态和构造方法的执行顺序

    1:访问修饰符 private     同类中 默认        同类        同包 protect    同类         同包      子类 public     同类        ...

  7. 请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。

    答:执行顺序:静态初始化块->初始化块->构造函数 静态初始化块:在第一次加载类时执行,与对象的创建无关. 构造代码块:在调用构造方法时执行. 构造函数:在调用构造函数时执行.

  8. C#静态类,静态构造函数,静态变量

    静态变量位于栈上,它是一个全局变量,在编译期就已经生成. public class Cow public static int count; private int id; { id = ++coun ...

  9. Java:构造器,构造代码块,静态代码块的执行顺序

    1.构造器:与类同名且没有返回值,用来初始化类属性: 构造器又分为无参构造器和有参构造器 1.1:无参构造器 public class Contruction{ ...属性... public Con ...

随机推荐

  1. 关于JS面向对象、设计模式、以及继承的问题总结

    1.对象:JS中万物皆对象,它是一个泛指 类:对象的具体的细分 (物以类聚,人与群分.具有相同属性和方法的实例的一个集合总称) 实例:某一个类别中具体的一个事物 对象是一个抽象的概念,类似于我们的自然 ...

  2. 【2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 G】Query on a string

    [链接]h在这里写链接 [题意] 让你维护字符串的一段区间内T子串的个数. [题解] 因为t不大,所以. 暴力维护一下a[i]就好. a[i]表示的是S串从i位置开始,能和T串匹配几个字符. 用树状数 ...

  3. VMware Ubuntu安装具体过程

    不是每个程序猿都必须玩过linux,仅仅是博主认为如今的非常多server都是linux系统的,而自己属于那种前端也搞.后台也搞,对框架搭建也感兴趣,可是非常多生产上的框架和工具都是安装在server ...

  4. ZOJ 2850和ZOJ 1414

    下午上数据结构,结果竟然没有新题.T T果断上OJ来水一发 ZOJ 2850   Beautiful Meadow 传送门http://acm.zju.edu.cn/onlinejudge/showP ...

  5. 6.4 Android硬件访问服务编写HAL代码

    JNI向上提供本地函数,向下加载HAL文件,并调用HAL的函数: HAL负责访问驱动程序执行硬件操作 JNI和HAL都是用c语言或者C++语言编写的,JNI加载HAL的实质就是使用dlopen加载动态 ...

  6. 3、C++快速入门

    参考书籍: C++程序设计教程_第二版_钱能    //篇幅较少,适合快速学习 C++ Primer Plus  第六版  中文版   //篇幅较大,讲的非常详细 C++一般必须包含的头文件是#inc ...

  7. VS2012 打包部署程序

      一. 下载 InstallShield 2015(支持VS2012) VS2012没有自带打包工具,所以要先下载并安装一个打包工具.我采用微软提供的打包工具:  InstallShield2015 ...

  8. 8、摄像头驱动_Linux的V4L2架构分析

    V4L2架构可以参考  linux-3.4.2\Documentation\video4linux\v4l2-framework.txt V4L2全名为Video For Linux 2,它是针对Li ...

  9. [Node.js] Testing ES6 Promises in Node.js using Mocha and Chai

    Writing great ES6 style Promises for Node.js is only half the battle. Your great modules must includ ...

  10. PWA之消息推送——Notification

    原文 简书原文:https://www.jianshu.com/p/69042b92cae1 大纲 1.推送通知的概念 2.消息推送的知识点 3.实例 1.推送通知的概念 大部分现代 Web 应用都需 ...