构造函数这个概念,在我们刚开始学习编程语言的时候,就被老师一遍一遍的教着。亲,现在你还记得静态构造函数的适用场景吗?如果没有,那么我们一起来复习一下吧。
静态构造函数是在构造函数方法前面添加了static关键字之后形成的,并且没有修饰符(public,private),没有参数。

静态构造函数有哪些特点呢:

  1. 静态构造函数没有修饰符修饰(public,private),因为静态构造函数不是我们程序员调用的,是由.net 框架在合适的时机调用的。
  2. 静态构造函数没有参数,因为框架不可能知道我们需要在函数中添加什么参数,所以规定不能使用参数。
  3. 静态构造函数前面必须是static 关键字。如果不加这个关键字,那就是普通的构造函数了。
  4. 静态构造函数中不能实例化实例变量。(变量可以分为类级别和实例级别的变量,其中类级别的有static关键字修饰)。
  5. 静态函数的调用时机,是在类被实例化或者静态成员被调用的时候进行调用,并且是由.net框架来调用静态构造函数来初始化静态成员变量。
  6. 一个类中只能有一个静态构造函数。
  7. 无参数的静态构造函数和无参数的构造函数是可以并存的。因为他们一个属于类级别,一个属于实例级别,并不冲突。
  8. 静态构造函数只会被执行一次。并且是在特点5中的调用时机中进行调用。
  9. 就像如果没有在类中写构造函数,那么框架会为我们生成一个构造函数,那么如果我们在类中定义了静态变量,但是又没有定义静态构造函数,那么框架也会帮助我们来生成一个静态构造函数来让框架自身来调用。

上面几个特点都是理论性的,我们来做一个找错题,帮助我们一起来学习静态构造函数。

public class C
{
public static string BB;
public static C()
{
BB = "CC";
}
public static C(string mm)
{
BB = mm;
}
static C()
{
BB = "Right";
}
public C()
{
BB = "Wrong";
}
public C(string mm)
{
BB = mm;
}
}

VS编译提示的错误信息:

现在我们来做一个有意思的事情,验证静态构造函数的调用时机:

class Program
{
static void Main(string[] args)
{ Console.WriteLine(A.strText);
Console.WriteLine(B.strText);
Console.Read();
}
}
public class A
{
public static string strText;
public string Text;
static A()
{
strText = "AAA";
}
public A()
{
Text = "AAAAAAAAAAAAAAAAAAAAAAAAAA";
}
}
public class B:A
{
static B()
{
strText = "BBB";
}
public B()
{
Text = "BBBBBBBBBBBBBBBBB";
}
}

输出结果均为:AAA
我们来分析一下出现这个情况的原因所在,当显示A.strText的时候,因为strText是静态变量,所以框架会调用A的静态构造函数,此时strText的值为AAA.正确
当显示B.strText的时候,因为B继承自A,所以会首先调用A的静态构造函数,但是因为静态构造函数只会调用一次,所以不会调用A的静态构造函数,但是又因为strText属于类A,而不是B,所以B得静态构造函数不会执行,故输出的均为AAA。

但是如果我们把输出更改一下,输出结果就大不一样了。

class Program
{
static void Main(string[] args)
{
B b = new B();
A a = new A(); Console.WriteLine(A.strText);
Console.WriteLine(B.strText); Console.Read();
}
}
public class A
{
public static string strText;
public string Text;
static A()
{
strText = "AAA";
}
public A()
{
Text = "AAAAAAAAAAAAAAAAAAAAAAAAAA";
}
}
public class B:A
{
static B()
{
strText = "BBB";
}
public B()
{
Text = "BBBBBBBBBBBBBBBBB";
}
}

请注意我在开始部分对类进行了实例化,那么此时的输出结果就是均为BBB。
为什么会有这样的情况出现呢,其实还是要从静态构造函数的调用时机入手。
首先我们实例化了B,此时会调用B的静态构造函数,但是因为strText是A的静态变量,所以首先会先调用A的静态构造函数将strText赋值为AAA,此时又会调用B的静态构造函数将strText赋值为BBB,所以此时strText的值应该为BBB,所以输出均为BBB。

我们再对代码进行更改,在类B中添加一个静态字符串变量strTextB,然后在B的静态构造函数中对strTextB赋值:

class Program
{
static void Main(string[] args)
{
Console.WriteLine(B.strText);
Console.WriteLine(B.strTextB);
Console.WriteLine(B.strText);
Console.Read();
}
}
public class A
{
public static string strText;
public string Text;
static A()
{
strText = "AAA";
}
public A()
{
Text = "AAAAAAAAAAAAAAAAAAAAAAAAAA";
}
}
public class B : A
{
public static string strTextB; static B()
{
strText = "BBB";
strTextB = "CCC";
}
public B()
{
Text = "BBBBBBBBBBBBBBBBB";
}
}

这一次,输出结果如下:

AAA

CCC

BBB

  • 首先在Main方法中,第一次使用B.strText访问了A的静态变量strText,所以此时A的静态构造函数被调用,因此B.strText输出AAA
  • 接着在Main方法中,B.strTextB访问了B的静态变量strTextB,所以此时B的静态构造函数被调用,因此此时B.strTextB的值为CCC,且此时B.strText变为了BBB
  • 最后在Main方法中,再次访问B.strText,此时A和B的静态构造函数都被调用过了,因此不会再被调用,但是B的静态构造函数在上一个步骤中已经将B.strText变为了BBB,所以此时B.strText输出BBB

接下来,我们再对代码做一个小的更改,这次我们在Main方法中先访问B.strTextB,再访问B.strText:

class Program
{
static void Main(string[] args)
{
Console.WriteLine(B.strTextB);
Console.WriteLine(B.strText);
Console.Read();
}
}
public class A
{
public static string strText;
public string Text;
static A()
{
strText = "AAA";
}
public A()
{
Text = "AAAAAAAAAAAAAAAAAAAAAAAAAA";
}
}
public class B : A
{
public static string strTextB; static B()
{
strText = "BBB";
strTextB = "CCC";
}
public B()
{
Text = "BBBBBBBBBBBBBBBBB";
}
}

输出结果如下:

CCC

BBB

那么这一次你是不是仿佛觉得A的静态构造函数没有被调用?实际上不是,我们来看看发生了什么:

首先在Main方法中,使用B.strTextB,会导致B的静态构造函数被调用,当B的静态构造函数执行strText = "BBB"对A的静态变量strText赋值时,由于strText是A的静态变量,且此时A的静态构造函数还没被调用过,所以此时会先调用A的静态构造函数,所以在这个时间点静态变量strText的值为AAA,但是当A的静态构造函数执行完毕后,紧接着B的静态构造函数立刻将静态变量strText又赋值为了BBB,所以在这个例子中,实际上是B的静态构造函数导致了A的静态构造函数被调用,静态变量strText首先被赋值为了AAA,但是紧接着B的静态构造函数又将静态变量strText赋值为了BBB

原文链接

c#静态构造函数 与 构造函数 你是否还记得?(转载)的更多相关文章

  1. c#静态构造函数 与 构造函数 你是否还记得?

    构造函数这个概念,在我们刚开始学习编程语言的时候,就被老师一遍一遍的教着.亲,现在你还记得静态构造函数的适用场景吗?如果没有,那么我们一起来复习一下吧. 静态构造函数是在构造函数方法前面添加了stat ...

  2. c#静态构造函数与构造函数

    构造函数这个概念,在我们刚开始学习编程语言的时候,就被老师一遍一遍的教着.亲,现在你还记得静态构造函数的适用场景吗?如果没有,那么我们一起来复习一下吧. 静态构造函数是在构造函数方法前面添加了stat ...

  3. java:利用静态字段和构造函数实现已建对象数查询

    问题:使用类的静态字段和构造函数,我们可以跟踪某个类所创建对象的个数. 请写一个类,在任何时候都可以向它查询"你已经创建了多少个对象?". 程序设计思想: 利用静态变量指定一个计数 ...

  4. c# 静态构造函数与构造函数的调用先后

    先上代码: 测试类: /// <summary> /// 构造函数 /// </summary> public RedisHelper() { Console.WriteLin ...

  5. C++类构造函数、拷贝构造函数、复制构造函数、复制构造函数、构造函数显示调用和隐式调用

    一. 构造函数是干什么的   class Counter   {   public:            // 类Counter的构造函数            // 特点:以类名作为函数名,无返回 ...

  6. C++的默认构造函数与构造函数

    今天看书,忽然发现自己对默认构造函数/构造函数的理解很模糊,在实际项目中写类时,这些细节问题并没有涉及到.因此,就专门对着<C++ Primer Plus>将默认构造函数/构造函数这一块简 ...

  7. python中的构造函数和构造函数和析构函数的作用

    构造函数和构造函数和析构函数都属于python中的特殊方法 其中的“__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用 ...

  8. 使用Code First建模自引用关系笔记 asp.net core上使用redis探索(1) asp.net mvc控制器激活全分析 语言入门必学的基础知识你还记得么? 反射

    使用Code First建模自引用关系笔记   原文链接 一.Has方法: A.HasRequired(a => a.B); HasOptional:前者包含后者一个实例或者为null HasR ...

  9. 《C#编程风格》还记得多少

    开始实习之后,才发现自己是多么地菜.还有好多东西还要去学习. 公司很好,还可以帮你买书.有一天随口问了一下上司D,代码规范上面有什么要求.然后D在Amazon上面找到了这本书<C#编程风格(Th ...

随机推荐

  1. BZOJ2820: YY的GCD(反演)

    题解 题意 题目链接 Sol 反演套路题.. 不多说了,就是先枚举一个质数,再枚举一个约数然后反演一下. 最后可以化成这样子 \[\sum_{i = 1}^n \frac{n}{k} \frac{n} ...

  2. html的标签分类————body内标签系列

    超链接标签 <a href="" target="_blank">text</a>,此类标签通常是超链接.其中href后面跟进的是超链接 ...

  3. 前端打包文件在 nginx 上 403 的解决办法

    遇到的问题表现出来就是如题所述,因此作为题目. 我们知道,前端有很多方便的构建和打包工具,如 webpack 等,通常我们会把前端文件打包到dist目录下,部署到服务器上,如 nginx 等. 这次遇 ...

  4. .NET代码设计简单规范

    以下转载于:http://www.it28.cn/ASPNET/825095.html 下面这个规范是我为朋友写的几点建议,写的很范,作为BLOG,愿与大家一起分享.只给出部分设计规范样例,关于.NE ...

  5. Java数据解析---PULL

    安卓和JAVA解析xml文件的三种方式: 1.PULL解析 2.SAX解析 3.DOM解析 三者各有所长,依情况选择解析方式 1.PULL和SAX均采用流式解析,意味着只能从头读到底,无法像DOM解析 ...

  6. MVC与单元测试实践之健身网站(完)-备案与部署

    主页-http://www.zhixin9001.cn/Home/Introduce GitHub- https://github.com/zhixin9001/Fitness 这是关于Fit网站的最 ...

  7. Android Java中的一些使用例子

    connectivity= ConnectivityService.getInstance(context); ServiceManager.addService(Context.CONNECTIVI ...

  8. [MapReduce_5] MapReduce 中的 Combiner 组件应用

    0. 说明 Combiner 介绍 &&  在 MapReduce 中的应用 1. 介绍 Combiner: Map 端的 Reduce,有自己的使用场景 在相同 Key 过多的情况下 ...

  9. 说说Android6.0动态申请权限的那些坑

    白天在做SDK23版本的适配,遇到了不少坑,现在抽空记下来,以此为戒. 首先要知道哪些坑,就得先了解一些定义和基本使用方式. 那么先介绍一下动态申请的权限分组情况. 下面的权限组是由谷歌官方定义的,目 ...

  10. Oracle 表操作(转)

    1.增加新字段:alter table table_name add (name varchar(20) default 'http://www.zangjing.net/');. 2.修改表字段:a ...