构造函数

构造函数分为:实例构造函数,静态构造函数,私有构造函数。

实例构造函数

1、构造函数的名字与类名相同。

2、使用 new 表达式创建类的对象或者结构(例如int)时,会调用其构造函数。并且通常初始化新对象的数据成员。

3、除非类是静态的,否则会为没有构造函数的类,自动生成一个默认构造函数,并使用默认值来初始化对象字段。

4、构造函数可以有参数,可以以多态的形式存在多个构造函数。

例:

  1. class CoOrds
  2. {
  3. public int x, y;
  4. // 实例构造函数(默认构造函数)
  5. public CoOrds()
  6. {
  7. x = ;
  8. y = ;
  9. }
  10. // 具有两个参数的构造函数
  11. public CoOrds(int x, int y)
  12. {
  13. this.x = x;
  14. this.y = y;
  15. }
  16. // 重写toString方法
  17. public override string ToString()
  18. {
  19. return (String.Format("({0},{1})", x, y));
  20. }
  21. static void Main(string[] args)
  22. {
  23. CoOrds p1 = new CoOrds();
  24. CoOrds p2 = new CoOrds(, );
  25.  
  26. // 使用重写ToString方法显示结果
  27. Console.WriteLine("CoOrds #1 at {0}", p1);
  28. Console.WriteLine("CoOrds #2 at {0}", p2);
  29. Console.ReadKey();
  30. }
  31. }
  32.  
  33. /* Output:
  34. CoOrds #1 at (0,0)
  35. CoOrds #2 at (5,3)
  36. */

其中CoOrds()是构造函数,诸如此类不带参数的构造函数称为“默认构造函数”。

CoOrds(int x, int y)同样也是构造函数,构造函数可以有参数,允许多态。

静态构造函数

静态构造函数具有以下属性:

  • 静态构造函数不使用访问修饰符或不具有参数。

  • 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数以初始化类。

  • 不能直接调用静态构造函数。

  • 用户无法控制在程序中执行静态构造函数的时间。

  • 静态构造函数的一种典型用法是在类使用日志文件且将构造函数用于将条目写入到此文件中时使用。

  • 静态构造函数对于创建非托管代码的包装类也非常有用,这种情况下构造函数可调用 LoadLibrary 方法。

  • 如果静态构造函数引发异常,运行时将不会再次调用该函数,并且类型在程序运行所在的应用程序域的生存期内将保持未初始化。

构造函数与静态构造函数:

  1. class TestClass
  2. {
  3. public static int x = ;
  4. //构造函数
  5. TestClass()
  6. {
  7. x = ;
  8. }
  9. //静态构造函数
  10. static TestClass()
  11. {
    //第二步,执行x = 2
  12. x = ;
  13. }
    //第一步,程序入口Main最先执行。然后执行public static int x = 0 接着执行静态构造函数。
  14. public static void Main(string[] args)
  15. {
  16. Console.WriteLine("x:{0}", x); //打印,x = 2
  17. TestClass Test = new TestClass();//第三步执行构造函数,此时x = 1
  18. Console.WriteLine("x:{0}", x); //打印 x = 1
  19. Console.Read();
  20. }
  21. }

Main是程序入口,当执行Main的时候,最先执行public static int x = 0

接着执行静态构造函数,此时 x = 2

然后执行Main函数里面的内容,打印 x,此时 x = 2

初始化TestClass,然后会执行构造函数,此时 x = 1

打印 x = 1

那么,在调用某类的静态函数时真正的执行顺序:

1、静态变量 > 静态构造函数 > 静态函数

2、静态变量 > 静态构造函数 > 构造函数

C#高效编程改进C#代码的50个行之有效的办法(第2版)里说到这样一段话:
类型实例的完整过程。你需要理解这些操作的顺序,以及对象的默认初始化操作。你要保证在构造的过程中对每个成员变量仅初始化一次。实现这一点最好的方法就是,尽可能的早地进行初始化。
下面就是创建某个类型的第一个实例时,所进行的操作顺序为:
(1)静态变量设置为0
(2)执行静态变量初始化器
(3)执行基类的静态构造函数
(4)执行静态构造函数
(5)实例变量设置为0
(6)执行衯变量初始化器
(7)执行基类中合适的实例构造函数
(8)执行实例构造函数 
同样类型的第二个以及以后的实例将从第5步开始执行,因为类的构造器仅会执行一次。此外,第6步和第7步将被优化,以便构造函数初始化器使编译器移除重复的指令。

练习题:(core项目下,答案不同)

  1. public class A
  2. {
  3. public static readonly int x;
  4. static A()
  5. {
  6. x = B.y + ;
  7. }
  8. }
  9.  
  10. public class B
  11. {
  12. public static int y = A.x + ;
  13. public static void Main(string[] args)
  14. {
  15. Console.WriteLine("x:{0},y:{1}。", A.x, y);
  16. Console.ReadLine();
  17. }
  18. }

下面公布答案:

  1. public class A
  2. {
  3. public static readonly int x;
  4. static A()
  5. {
  6. //第二步,调用B.y,此处B.y = 0,因为int类型在初始化阶段,会给赋默认值,默认值为0。最后x = 0 + 1(返回给第一步)
  7. x = B.y + ;
  8. }
  9. }
  10.  
  11. public class B
  12. {
  13. //第一步,调用A.x,然后执行类A的静态构造函数,等待返回(第二步返回的A.x = 1,所以y = 1 + 1)
  14. public static int y = A.x + ;
  15. public static void Main(string[] args)
  16. {
  17. //第三步,A.x = 1,y = 2。
  18. Console.WriteLine("x:{0},y:{1}。", A.x, y);
  19. Console.ReadLine();
  20. }
  21. }

练习题答案

详细解答:

1、首先,每一个项目有且只能有一个静态类的Main函数作为入口函数。而入口函数是最先执行的。

2、由于Main函数在B类里面,首先会初始化B类。而类的初始化顺序是:类里的静态变量,然后执行静态构造函数。

3、运行起先执行 public static int y = A.x + 1 这个,执行的时候,会先把 y 初始化为0,然后计算 y 的值。

4、计算 y 的值的时候,调用了 A 的静态变量 x 。所以会先初始化A。

5、初始化A时首先去执行 public static readonly int x ,先把 x 初始化为0。

6、然后执行A的静态构造函数 x = B.y + 1 此时 y 已经初始化为0了。

7、计算得到 x = 1。然后回到 public static int y = A.x + 1 得到 y = 2。

8、然后再执行Main函数的内容。得出结果x=1,y=2

补充: 小鹏Y 提出了 .net core 项目下得出的答案有出入。非常感谢他!以下是 .net core 项目的角度

在第二步计算 x = B.y + 1,B.y 的值是1,不是0。 所以在计算 x = B.y + 1 的时候,x = 2。

最后的结果变成:A.x = 2,y = 1

具体为何这样,还不清楚,此篇文章目前只考虑非 core 项目的情况。

私有构造函数

私有构造函数是一种特殊的实例构造函数。 它通常用于只包含静态成员的类中。 如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例。

  1. public class PrivateConstructor
  2. {
  3. private PrivateConstructor()
  4. {
  5. //PrivateTest a = new PrivateTest(); //注释打开会报错,错误信息:不可访问,因为它受保护级别限制。因为私有构造函数无法在类的外面实例化。
  6. }
  7. public class PrivateTest
  8. {
  9. int i;
  10. private PrivateTest()
  11. {
  12. i = ;
  13. }
  14. static void Main(string[] args)
  15. {
  16. PrivateConstructor t = new PrivateConstructor(); //嵌套类允许实例化。
  17. PrivateTest p = new PrivateTest(); //类的内部允许实例化。
  18. Console.WriteLine("i:{0}", p.i); //结果:i:3
  19. Console.Read();
  20. }
  21. }
  22. }

声明空构造函数可阻止自动生成默认构造函数。 请注意,如果不对构造函数使用访问修饰符,则在默认情况下它仍为私有构造函数。 但是,通常会显式地使用 private 修饰符来清楚地表明该类不能被实例化。

实例:

其中单例模式就用到了私有构造函数的特性来保证类不会被实例化。C# 单例模式


相关文章: http://www.cnblogs.com/michaelxu/archive/2007/03/29/693401.html

https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/constructors

C# 构造函数总结的更多相关文章

  1. .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]

    构造函数.析构函数 构造函数: 语法: //无参的构造函数 [访问修饰符] 函数名() :函数名必须与类名相同. //有参的构造函数 [访问修饰符] 函数名(参数列表):函数名必须与类名相同. 作用: ...

  2. javascript工厂模式和构造函数模式创建对象

    一.工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程(本书后面还将讨论其他设计模式及其在JavaScript 中的实现).考虑到在ECMAScript 中无法创 ...

  3. JS继承之借用构造函数继承和组合继承

    根据少一点套路,多一点真诚这个原则,继续学习. 借用构造函数继承 在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数(constructor stealing)的技术( ...

  4. PHP与JAVA构造函数的区别

    早期的PHP是没有面向对象功能的,但是随着PHP发展,从PHP4开始,也加入了面向对象.PHP的面向对象语法是从JAVA演化而来,很多地方类似,但是又发展出自己的特色.以构造函数来说,PHP4中与类同 ...

  5. C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ...

  6. golang语言构造函数

    1.构造函数定义 构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.特别的一个类可以有多个构造函数 ,可根据其参数个 ...

  7. 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型

    前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...

  8. Aop动态生成代理类时支持带参数构造函数

    一.背景 在某些情况下,我们需要植入AOP代码的类并没有默认构造函数.那么此时动态生成的代理类也需要相同签名的构造函数,并且内部调用原始类的构造函数.自己折腾了1晚上没搞定,现在搞定了发出来供大家一起 ...

  9. C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?

    Review后看到标题让我十分羞愧自己语文功底太差,估计...请见谅......我还特地把这句写回开头了...... 问题 前天遇到的一个问题,所以在MSDN发了个问,刚也丰富了下问题,关于泛型的. ...

  10. Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

    零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...

随机推荐

  1. Natas Wargame Level27 Writeup(SQL表的注入/溢出与截取)

    前端: <html> <head> <!-- This stuff in the header has nothing to do with the level --&g ...

  2. IDEA热部署(一)---解析关键配置。

    本编博客转载自:因为自己在研究热部署,包括热部署那些文件,部署实现的包括那些操作.这一块,所以这篇好博客. http://www.mamicode.com/info-detail-1699044.ht ...

  3. 《计算机程序的构造和解释(第2版)》【PDF】下载

    <计算机程序的构造和解释(第2版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382255 内容简介 <计算机程序的构造 ...

  4. 《决战大数据:驾驭未来商业的利器》【PDF】下载

    内容简介 大数据时代的来临,给当今的商业带来了极大的冲击,多数电商人无不"谈大数据色变",并呈现出一种观望.迷茫.手足无措的状态.车品觉,作为一名经验丰富的电商人,在敬畏大数据的同 ...

  5. 【批处理】IF ERRORLEVER语句顺序注意

    @echo off dir d:\dddddd if errorlevel 1 goto 1 if errorlevel 0 goto 0 rem 两行if语句不可交换位置,否则失败了也会显示成功. ...

  6. Android 环境搭建、基础窗口window/Mac

    1.五步搞定Android开发环境部署--非常详细的Android开发环境搭建教程 2.Android开发学习之路--MAC下Android Studio开发环境搭建 4.Android常用开发工具以 ...

  7. 507. Perfect Number

    We define the Perfect Number is a positive integer that is equal to the sum of all its positive divi ...

  8. ArcGIS API for JavaScript 4.2学习笔记[8] 2D与3D视图同步

    同一份数据不同视图查看可能用的比较少,因为3D视图放大很多后就和2D地图差不多了,畸变很小,用于超大范围的地图显示时有用,很多时候都是在平面地图上进行分析.查询.操作.教学需要可能会对这个有要求? 本 ...

  9. Python学习(一):编写购物车

    1.购物车流程图: 2.代码实现: #!/usr/bin/env python #coding=utf-8 ChoiceOne =''' 1.查看余额 2.购物 3.退出 ''' ChoiceTwo ...

  10. uEditor富文本编辑器

    在配合vue和webpack使用时,在严格模式下注意会报错,需要修改配置. 我采用的方式:----不建议全部取消严格模式,因为一些插件必须要再严格模式才能运行的 对UEditor的严格模式报错文件,取 ...