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

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

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. { //执行顺序5
  5. var de = new People("2"); //执行顺序6
  6. People.Instance.OutDemo(); //执行顺序8
  7.  
  8. Console.ReadKey(); //执行顺序10
  9. }
  10.  
  11. }
  12.  
  13. public class People
  14. {
  15. public void OutDemo()
  16. { //执行顺序9
  17. Console.WriteLine($"HaHa");
  18. }
  19.  
  20. public static readonly People Instance = new People(); //执行顺序1
  21.  
  22. public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序4
  23.  
  24. private People()
  25. { //执行顺序2
  26. Console.WriteLine(3); //执行顺序3
  27. }
  28.  
  29. public People(string ss)
  30. { //执行顺序7
  31.  
  32. }
  33. }

 

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

  1. class Program
  2. {
  3. static Program()
  4. { //然后执行
  5.  
  6. }
  7.  
  8. static void Main(string[] args)
  9. {
  10.  
  11. var de = new People("2");
  12. People.Instance.OutDemo();
  13.  
  14. Console.ReadKey(); //执行顺序10
  15. }
  16.  
  17. public static string sdds = "sdds"; //最先执行
  18. }

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

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

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

  1. class Program
  2. {
  3. static Program()
  4. { //然后执行
  5.  
  6. }
  7.  
  8. static void Main(string[] args)
  9. { 执行顺序1
  10.  
  11. var de = new People("2"); 执行顺序2
  12. People.Instance.OutDemo(); //执行顺序8
  13.  
  14. Console.ReadKey();
  15. }
  16.  
  17. public static string sdds = "sdds"; //最先执行
  18. }
  19.  
  20. public class People
  21. {
  22.  
  23. static People()
  24. { //执行顺序7
  25.  
  26. }
  27.  
  28. public void OutDemo()
  29. { //执行顺序9
  30. Console.WriteLine($"HaHa");
  31. }
  32.  
  33. public static readonly People Instance = new People(); //执行顺序3
  34.  
  35. public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序6
  36.  
  37. private People()
  38. { //执行顺序4
  39. Console.WriteLine(3); //执行顺序5
  40. }
  41.  
  42. public People(string ss)
  43. { //执行顺序7
  44.  
  45. }
  46. }

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

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

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

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

  1. .....
  2.  
  3. public static readonly People Instance = new People(); //执行顺序3
  4.  
  5. public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序7
  6.  
  7. private People()
  8. { //执行顺序5
  9. var d= Money.Count //执行顺序6
  10. Console.WriteLine(3);
  11. }
  12.  
  13. ........
  14.  
  15. public class Money
  16. {
  17. public static int Count= "4"; //执行顺序4
  18. }
  19.  
  20. ......

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

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

  1. .....
  2.  
  3. static People()
  4. { //执行顺序10
  5.  
  6. }
  7.  
  8. public static readonly People Instance = new People(); //执行顺序3
  9.  
  10. public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序9
  11.  
  12. private People()
  13. { //执行顺序4
  14. var d= Money.Count //执行顺序5
  15. Console.WriteLine(3); //执行顺序8
  16. }
  17.  
  18. ........
  19.  
  20. public class Money
  21. {
  22. static Money()
  23. { //执行顺序7
  24.  
  25. }
  26.  
  27. public static int Count= "4"; //执行顺序6
  28. }
  29.  
  30. ......

依然符合。结论依然牢固

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

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

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

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

改造起来

  1. class Program
  2. {
  3. static Program()
  4. { //然后执行
  5.  
  6. }
  7.  
  8. static void Main(string[] args)
  9. { 执行顺序1
  10.  
  11. // var de = new People("2");
  12. //People.Instance.OutDemo();
  13. People.xixi(); //执行顺序2
  14.  
  15. Console.ReadKey(); //执行顺序8
  16. }
  17.  
  18. public static string sdds = "sdds"; //最先执行
  19. }
  20.  
  21. public class People
  22. {
  23.  
  24. public static string xixi()
  25. { //执行顺序7
  26. return "xixi";
  27. }
  28.  
  29. public void OutDemo()
  30. {
  31. Console.WriteLine($"HaHa");
  32. }
  33.  
  34. public static readonly People Instance = new People(); //执行顺序3
  35.  
  36. public static Action Inssstance = () => { Console.WriteLine("11"); }; //执行顺序6
  37.  
  38. private People()
  39. { //执行顺序4
  40. Console.WriteLine(3); //执行顺序5
  41. }
  42.  
  43. public People(string ss)
  44. {
  45.  
  46. }
  47. }

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

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

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

如果对调用层做个包装呢

  1.  
  2. ....
  3. static void Main(string[] args)
  4. { //执行顺序1
  5. dtas(); //执行顺序2
  6. // Console.WriteLine(People.Instance.OutDemo());
  7. Console.ReadKey();
  8. }
  9.  
  10. public static void dtas()
  11. { //执行顺序4
  12. People.Instance.OutDemo();
  13. }
  14.  
  15. .......
  16.  
  17. //假设People没有静态构造函数
  18.  
  19. ......
  20.  
  21. //public static readonly People Instance = new People(); //执行顺序3
  22.  
  23. ....

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

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

  1. ......
  2.  
  3. static void Main(string[] args)
  4. { 执行顺序2
  5.  
  6. People.Instance().OutDemo(); 执行顺序3
  7.  
  8. Console.ReadKey(); //执行顺序7
  9. }
  10.  
  11. .......
  12.  
  13. //假设People没有静态构造函数
  14.  
  15. ......
  16.  
  17. //public static readonly People Instance = new People();
  18. //换成下面这中
  19. public static readonly Func Instance = () => { 执行顺序1
  20. return new People(); 执行顺序4
  21. };
  22.  
  23. public void OutDemo()
  24. { 执行顺序5
  25. Console.WriteLine($"HaHa"); 执行顺序6
  26. }
  27.  
  28. .......

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

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

  1. class Class1
  2. {
  3.  
  4. static void Main(string[] args)
  5. { //执行顺序 6
  6. var obj = People.Instance; //执行顺序 7
  7.  
  8. Console.Read(); //执行顺序 8
  9. }
  10. }
  11.  
  12. public class People
  13. {
  14. public static readonly ZIS2 Instance = Middle.mid; //执行顺序 4
  15.  
  16. public static string dsds = "sdd"; //执行顺序 5
  17. }
  18.  
  19. public class Middle
  20. {
  21. public static ZIS2 mid = ZIS2.Instance; //执行顺序 3
  22.  
  23. }
  24.  
  25. public class ZIS2
  26. {
  27. public static ZIS2 Instance = new ZIS2(); //执行顺序 1
  28.  
  29. private ZIS2()
  30. { //执行顺序 2
  31.  
  32. }
  33. }

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

来看下 下片的介绍:关于 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实现动画方向切换效果(包括:撞墙反弹,暂停继续左右运动等)

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  2. Docker---(2)docker pull 下来的镜像存储在哪里

    原文:Docker---(2)docker pull 下来的镜像存储在哪里 版权声明:欢迎转载,请标明出处,如有问题,欢迎指正!谢谢!微信:w1186355422 https://blog.csdn. ...

  3. IE block my cookie in iframe

    ---恢复内容开始--- There is a severe bug that a leader figured it out in a published project. In IE11, the ...

  4. /bin/bash^M: bad interpreter: 没有那个文件或文件夹

    执行脚本时出现了这样一个错误,打开之后并没有找到所谓的^M,查了之后才知道原来是文件格式的问题,也就是linux和windows之间的不全然兼容... 详细细节无论,假设验证: vim test.sh ...

  5. MCI

    MCI(Media Control Interface)媒体控件接口是Mircrosoft提供的一组多媒体和文件的标准接口.它的好处是可以方便地控制绝大多数多媒体设备 包括音频,视频,影碟,录像等多媒 ...

  6. 【19.77%】【codeforces 570D】Tree Requests

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  7. [Angular2 Form] Create custom form component using Control Value Accessor

    //switch-control component import { Component } from '@angular/core'; import { ControlValueAccessor, ...

  8. Html表单中遇到的问题

    原文 https://www.jianshu.com/p/4466b8294007 大纲 1.表单提交的方式GET和POST的区别 2.js无法对input的file类型的值进行赋值 3.js获取in ...

  9. 在Linux上安装及配置MariaDB

    安装MariaDB 1.切换到root用户,首先执行rpm -qa | grep -i mysql检查一下是否有已安装的与MySQL相关的东西,如果有,使用rpm -e --nodeps mysql* ...

  10. [Recompose] Add Local State to a Functional Stateless Component using Recompose

    Learn how to use the 'withState' and 'withHandlers' higher order components to easily add local stat ...