构造函数

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

实例构造函数

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

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

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

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

例:

class CoOrds
{
public int x, y;
// 实例构造函数(默认构造函数)
public CoOrds()
{
x = ;
y = ;
}
// 具有两个参数的构造函数
public CoOrds(int x, int y)
{
this.x = x;
this.y = y;
}
// 重写toString方法
public override string ToString()
{
return (String.Format("({0},{1})", x, y));
}
static void Main(string[] args)
{
CoOrds p1 = new CoOrds();
CoOrds p2 = new CoOrds(, ); // 使用重写ToString方法显示结果
Console.WriteLine("CoOrds #1 at {0}", p1);
Console.WriteLine("CoOrds #2 at {0}", p2);
Console.ReadKey();
}
} /* Output:
CoOrds #1 at (0,0)
CoOrds #2 at (5,3)
*/

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

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

静态构造函数

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

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

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

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

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

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

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

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

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

class TestClass
{
public static int x = ;
//构造函数
TestClass()
{
x = ;
}
//静态构造函数
static TestClass()
{
//第二步,执行x = 2
x = ;
}
//第一步,程序入口Main最先执行。然后执行public static int x = 0 接着执行静态构造函数。
public static void Main(string[] args)
{
Console.WriteLine("x:{0}", x); //打印,x = 2
TestClass Test = new TestClass();//第三步执行构造函数,此时x = 1
Console.WriteLine("x:{0}", x); //打印 x = 1
Console.Read();
}
}

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项目下,答案不同)

public class A
{
public static readonly int x;
static A()
{
x = B.y + ;
}
} public class B
{
public static int y = A.x + ;
public static void Main(string[] args)
{
Console.WriteLine("x:{0},y:{1}。", A.x, y);
Console.ReadLine();
}
}

下面公布答案:

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

练习题答案

详细解答:

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 项目的情况。

私有构造函数

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

public class PrivateConstructor
{
private PrivateConstructor()
{
//PrivateTest a = new PrivateTest(); //注释打开会报错,错误信息:不可访问,因为它受保护级别限制。因为私有构造函数无法在类的外面实例化。
}
public class PrivateTest
{
int i;
private PrivateTest()
{
i = ;
}
static void Main(string[] args)
{
PrivateConstructor t = new PrivateConstructor(); //嵌套类允许实例化。
PrivateTest p = new PrivateTest(); //类的内部允许实例化。
Console.WriteLine("i:{0}", p.i); //结果:i:3
Console.Read();
}
}
}

声明空构造函数可阻止自动生成默认构造函数。 请注意,如果不对构造函数使用访问修饰符,则在默认情况下它仍为私有构造函数。 但是,通常会显式地使用 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. MPSOC之4——petalinux提取源码

    petalinux使用太不方便,捆绑的太死板,也不通用,还不如直接用编译器来的简单高效. 本文说明从petalinux中提取出源代码的过程,前提是已经petalinux-build完成. 1. ubo ...

  2. web前端开发 --好多视频大集合--文化的传播者-杜恩德

    提醒: 如果需要的话,尽快保存,说不定哪天分享就消失了呢. 1.妙味WEB前端开发全套视频教程 链接: http://pan.baidu.com/s/1bf1Ow2 密码: 2yyu 2.极客学院前端 ...

  3. mac配置java和maven环境变量

    1.打开终端: 2.输入命令:sudo vi ~/.bash_profile进入编辑模式: 3.输入开机密码并按两次enter键进入编辑选择项: 4.输入i键进入文件插入模式输入配置信息: 5.按es ...

  4. SQLMap安装步骤

    SQLMap是利用Python语言写的,所以需要将Python这个语言环境给安装上 : 1.首先下载Python(这里Python版本为2.7.2,可以下载不同或高版本的) 2.然后在下载sqlmap ...

  5. iOS 计时器三种定时器的用法NSTimer、CADisplayLink、GCD

    原文:http://www.cocoachina.com/ios/20160919/17595.html DEMO链接

  6. iOS 接收新消息通知调用系统声音 震动

    添加系统框架: #import <AudioToolbox/AudioToolbox.h> 调用震动代码: AudioServicesPlaySystemSound(kSystemSoun ...

  7. 安装cocoa pods时出现Operation not permitted - /usr/bin/xcodeproj的问题

    安装cocoa pods时, 在命令行中输入: 安装:sudo gem install cocoapods报Operation not permitted - /usr/bin/xcodeproj这个 ...

  8. react native仿微信性别选择-自定义弹出框

    简述 要实现微信性别选择需要使用两部分的技术: 第一.是自定义弹出框: 第二.单选框控件使用: 效果 实现 一.配置弹出框 弹出框用的是:react-native-popup-dialog(Git地址 ...

  9. HDFS租约实践

    一.租约详解 Why租约 HDFS的读写模式为 "write-once-read-many",为了实现write-once,需要设计一种互斥机制,租约应运而生租约本质上是一个有时间 ...

  10. zepto的返回顶部scrollTop的动画解决方法

    写移动端的时候,引入的zepto.js里的animate不包括scrollTop,所以返回顶部的时候,没有动画的效果.这里我使用的是setInterval的方法.代码详情如下 <!DOCTYPE ...