c#静态构造函数 与 构造函数 你是否还记得?(转载)
构造函数这个概念,在我们刚开始学习编程语言的时候,就被老师一遍一遍的教着。亲,现在你还记得静态构造函数的适用场景吗?如果没有,那么我们一起来复习一下吧。
静态构造函数是在构造函数方法前面添加了static关键字之后形成的,并且没有修饰符(public,private),没有参数。
静态构造函数有哪些特点呢:
- 静态构造函数没有修饰符修饰(public,private),因为静态构造函数不是我们程序员调用的,是由.net 框架在合适的时机调用的。
- 静态构造函数没有参数,因为框架不可能知道我们需要在函数中添加什么参数,所以规定不能使用参数。
- 静态构造函数前面必须是static 关键字。如果不加这个关键字,那就是普通的构造函数了。
- 静态构造函数中不能实例化实例变量。(变量可以分为类级别和实例级别的变量,其中类级别的有static关键字修饰)。
- 静态函数的调用时机,是在类被实例化或者静态成员被调用的时候进行调用,并且是由.net框架来调用静态构造函数来初始化静态成员变量。
- 一个类中只能有一个静态构造函数。
- 无参数的静态构造函数和无参数的构造函数是可以并存的。因为他们一个属于类级别,一个属于实例级别,并不冲突。
- 静态构造函数只会被执行一次。并且是在特点5中的调用时机中进行调用。
- 就像如果没有在类中写构造函数,那么框架会为我们生成一个构造函数,那么如果我们在类中定义了静态变量,但是又没有定义静态构造函数,那么框架也会帮助我们来生成一个静态构造函数来让框架自身来调用。
上面几个特点都是理论性的,我们来做一个找错题,帮助我们一起来学习静态构造函数。
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#静态构造函数 与 构造函数 你是否还记得?(转载)的更多相关文章
- c#静态构造函数 与 构造函数 你是否还记得?
构造函数这个概念,在我们刚开始学习编程语言的时候,就被老师一遍一遍的教着.亲,现在你还记得静态构造函数的适用场景吗?如果没有,那么我们一起来复习一下吧. 静态构造函数是在构造函数方法前面添加了stat ...
- c#静态构造函数与构造函数
构造函数这个概念,在我们刚开始学习编程语言的时候,就被老师一遍一遍的教着.亲,现在你还记得静态构造函数的适用场景吗?如果没有,那么我们一起来复习一下吧. 静态构造函数是在构造函数方法前面添加了stat ...
- java:利用静态字段和构造函数实现已建对象数查询
问题:使用类的静态字段和构造函数,我们可以跟踪某个类所创建对象的个数. 请写一个类,在任何时候都可以向它查询"你已经创建了多少个对象?". 程序设计思想: 利用静态变量指定一个计数 ...
- c# 静态构造函数与构造函数的调用先后
先上代码: 测试类: /// <summary> /// 构造函数 /// </summary> public RedisHelper() { Console.WriteLin ...
- C++类构造函数、拷贝构造函数、复制构造函数、复制构造函数、构造函数显示调用和隐式调用
一. 构造函数是干什么的 class Counter { public: // 类Counter的构造函数 // 特点:以类名作为函数名,无返回 ...
- C++的默认构造函数与构造函数
今天看书,忽然发现自己对默认构造函数/构造函数的理解很模糊,在实际项目中写类时,这些细节问题并没有涉及到.因此,就专门对着<C++ Primer Plus>将默认构造函数/构造函数这一块简 ...
- python中的构造函数和构造函数和析构函数的作用
构造函数和构造函数和析构函数都属于python中的特殊方法 其中的“__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用 ...
- 使用Code First建模自引用关系笔记 asp.net core上使用redis探索(1) asp.net mvc控制器激活全分析 语言入门必学的基础知识你还记得么? 反射
使用Code First建模自引用关系笔记 原文链接 一.Has方法: A.HasRequired(a => a.B); HasOptional:前者包含后者一个实例或者为null HasR ...
- 《C#编程风格》还记得多少
开始实习之后,才发现自己是多么地菜.还有好多东西还要去学习. 公司很好,还可以帮你买书.有一天随口问了一下上司D,代码规范上面有什么要求.然后D在Amazon上面找到了这本书<C#编程风格(Th ...
随机推荐
- 2018-01-11 Antlr4的分析错误处理
中文编程知乎专栏原文地址 (前文通用型的中文编程语言探讨之一: 高考, 即使是这"第一步", 即使一切顺利达到列出的功能恐怕也需要个人数年的业余时间. 看到不少乎友都远更有资本和实 ...
- 【读书笔记】iOS-viewWillAppear:和viewDidLoad:
viewDidLoad:是视图第一次载入到内存中后调用的,viewWillApear:则是在每次视图显示到屏幕上之前调用. 参考资料:<iOS编程指南>
- JS性能优化 之 事件委托
面试中2次被问到过这个知识点,实际开发中,应用事件委托也比较常见.JS中事件委托的实现主要依赖于 事件冒泡 .那什么是事件冒泡?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一 ...
- Kotlin入门(7)循环语句的操作
上一篇文章介绍了简单分支与多路分支的实现,控制语句除了这两种条件分支之外,还有对循环处理的控制,那么本文接下来继续阐述Kotlin如何对循环语句进行操作. Koltin处理循环语句依旧采纳了for和w ...
- 关于web优化(一)
我们所说的web,无非就是html,css(web font, image),JavaScript. HTML优化建议: 1. 尽量不要用table进行布局. 2. 尽量用最新的带有语义的h5标签,这 ...
- Echarts地图展示及属性分析
Echarts,一个效果非常棒的可视化库,可以生产各种图表,动态展示,附上官方网址:http://www.echartsjs.com/index.html 之前带本科实习时有同学用过,狗哥的博客也用这 ...
- [20180627]测试bbed是否支持管道命令.txt
[20180627]测试bbed是否支持管道命令.txt --//测试bbed是否支持管道命令.txt 1.环境:SCOTT@test01p> @ ver1PORT_STRING ...
- python第四十九天--paramiko模块安装大作战
准备开始学习:paramiko模块,发现这个模块十分难搞 安装不上 搞了半天,win10 64下 pytyon 3.6 的 paramiko模块 死活安不上,在网上不断的找资料,可是没有用,没有用啊 ...
- 根据id来大量删除数据between
id的范围来删除数据 比如要删除 110到220的id信息:delete id from 表名 where id between 110 and 220;
- VB6 对象库未注册问题
以下是个人使用VB6出现对象库未注册问题的解决方法.已成功! 一.注册ocx文件 mscomctl.ocx文件放进路径C:\Windows\System32(64是此路径,由于本人是64位系统32位未 ...