C# 构造函数总结
构造函数
构造函数分为:实例构造函数,静态构造函数,私有构造函数。
实例构造函数
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、静态变量 > 静态构造函数 > 构造函数
类型实例的完整过程。你需要理解这些操作的顺序,以及对象的默认初始化操作。你要保证在构造的过程中对每个成员变量仅初始化一次。实现这一点最好的方法就是,尽可能的早地进行初始化。
下面就是创建某个类型的第一个实例时,所进行的操作顺序为:
(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# 构造函数总结的更多相关文章
- .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]
构造函数.析构函数 构造函数: 语法: //无参的构造函数 [访问修饰符] 函数名() :函数名必须与类名相同. //有参的构造函数 [访问修饰符] 函数名(参数列表):函数名必须与类名相同. 作用: ...
- javascript工厂模式和构造函数模式创建对象
一.工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程(本书后面还将讨论其他设计模式及其在JavaScript 中的实现).考虑到在ECMAScript 中无法创 ...
- JS继承之借用构造函数继承和组合继承
根据少一点套路,多一点真诚这个原则,继续学习. 借用构造函数继承 在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数(constructor stealing)的技术( ...
- PHP与JAVA构造函数的区别
早期的PHP是没有面向对象功能的,但是随着PHP发展,从PHP4开始,也加入了面向对象.PHP的面向对象语法是从JAVA演化而来,很多地方类似,但是又发展出自己的特色.以构造函数来说,PHP4中与类同 ...
- C++ 拷贝构造函数和赋值运算符
本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ...
- golang语言构造函数
1.构造函数定义 构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.特别的一个类可以有多个构造函数 ,可根据其参数个 ...
- 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型
前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...
- Aop动态生成代理类时支持带参数构造函数
一.背景 在某些情况下,我们需要植入AOP代码的类并没有默认构造函数.那么此时动态生成的代理类也需要相同签名的构造函数,并且内部调用原始类的构造函数.自己折腾了1晚上没搞定,现在搞定了发出来供大家一起 ...
- C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?
Review后看到标题让我十分羞愧自己语文功底太差,估计...请见谅......我还特地把这句写回开头了...... 问题 前天遇到的一个问题,所以在MSDN发了个问,刚也丰富了下问题,关于泛型的. ...
- Android中自定义样式与View的构造函数中的第三个参数defStyle的意义
零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...
随机推荐
- 使用docker+consul+nginx集成分布式的服务发现与注册架构
一.环境说明: 1.一台虚拟机,该系统已经装好了docker: ip 192.168.10.224 虚拟网卡,与主机互通 操作系统rhel6 内核 2.6.32 64位 docker版本 1.7.1 ...
- 【ANT】description元素和属性
<?xml version="1.0" ?> <project default="test"> <description> ...
- sqlserver 存储过程 删除
--删除(delete from) CREATE PROCEDURE [dbo].[DeleteMessage] @strtable varchar(),--要删除信息的表名 @strwhere va ...
- 字符串输入时的strlen()与\0
在做串的数据结构时,被字符串printf %s输出时的结尾判断.strlen();长度.自定义StrCopy();字符串复制函数.StrAssign();字符串赋值函数卡了一下,固写此博巩固相关知识点 ...
- 将Maven的Web项目部署到windows的Tomcat里
这里我用的是win7和tomcat8,且tomcat8下载的是压缩包而非安装文件. 第一步:先将tomcat8安装服务,cmd里更改目录为tomcat8(即压缩包解压后的那个文件夹)的bin文件夹, ...
- 视觉SLAM中相机详解
视觉SLAM中,通常是指使用相机来解决定位和建图问题. SLAM中使用的相机往往更加简单,不携带昂贵的镜头,以一定的速率拍摄周围的环境,形成一个连续的视频流. 相机分类: 单目相机:只是用一个摄像头进 ...
- lesson - 10 课程笔记
CTRL+C CTRL+D :前者用于结束一个程序,后者用于结束终端输入. --符号 *:匹配任意长度的任意字符 ?:匹配任意一个字符 #: shell 中表注释 \: 脱意符号 []:任意属于字符组 ...
- Nginx (三) 使用Keepalived搭建高可用服务
Nginx可以实现高并发反向代理,实现负载均衡,但是有个问题就是Nginx是单点的.如果Nginx故障,则整个服务将会处于不可用状态.所以我们就需要想办法让nginx高可用,即使一个Nginx宕机,还 ...
- Linux(CentOS7.1)修改默认yum源为国内的阿里云yum源
官方的yum源在国内访问效果不佳. 需要改为国内比较好的阿里云或者网易的yum源 修改方式: 下载wget yum install wget -y echo 备份当前的yum源 mv /etc/yum ...
- java调优(一)