C# 构造函数总结

阅读目录

构造函数

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

实例构造函数

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

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

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

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

例:

class CoOrds
{
    public int x, y;
    // 实例构造函数(默认构造函数)
    public CoOrds()
    {
        x = 0;
        y = 0;
    }
    // 具有两个参数的构造函数
    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(5, 3);

        // 使用重写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 = 0;
    //构造函数
    TestClass()
    {
        x = 1;
    }
    //静态构造函数
    static TestClass()
    {        //第二步,执行x = 2
        x = 2;
    }    //第一步,程序入口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 + 1;
    }
}

public class B
{
    public static int y = A.x + 1;
    public static void Main(string[] args)
    {
        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 = 3;
        }
        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

原文地址:https://www.cnblogs.com/wfy680/p/12044295.html

时间: 2024-08-04 12:32:56

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

【转载】C++拷贝构造函数(深拷贝,浅拷贝)

对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. #include <iostream>using namespace std;class CExample {private:     int a;public:     CExample(int b)     { a=b;}     void Show ()     {        cout<

C++程序设计方法3:移动构造函数

移动拷贝构造函数 语法: ClassName(ClassName&&); 目的: 用来偷"临时变量"中的资源(比如内存) 临时变量被编译器设置为常量形式,使用拷贝构造函数无法将资源偷出来("偷"是对原来对象的一种改动,违反常量的限制) 基于"右值引用"定义的移动构造函数支持接受临时变量,能偷出临时变量中的资源: #include <iostream> using namespace std; class Test {

父类的构造函数在对象的生命中扮演的角色

在创建新对象时,所有继承下来的构造函数都会被继承 这代表着每个父类都有一个构造函数(因为每个类至少都会有一个构造函数),并且每个构造函数都会在对象创建时执行. 执行new的指令是个大事件,因为他会启动构造函数的连锁反应.还有,就算是抽象的类也有构造函数.虽然你不能对抽象函数执行new操作,但是抽象函数还是父类,因此它的构造函数会在具体的子类创建实例时被执行. 在构造函数中用super调用父类的构造函数部分(注意:调用super() 方法是调用父类构造函数的唯一方法).要记得子类会根据父类的状态进

JavaScript中的构造函数

function Accom(){};    //创建一个构造函数 //创建两个对象 var house=new Accom(); var apartment=new Accom(); 通过构造函数创建的对象有一个属性constructor,这个属性指向创建该对象时所用的Javascript构造函数. house.constructor===Accom;  或者   house instanceof Accom;     //true JavaScript中的每个构造函数都有一个prototyp

javascript中的构造函数和原型及原型链

纯属个人理解,有错误的地方希望大牛指出,以免误人子弟 1.构造函数: 构造函数的作用 : 初始化由new创建出来的对象    new 的作用: 创建对象(空对象) new 后面跟的是函数调用,使用new来调用函数,跟普通的直接调用函数主要的不同: 就是 this 的指向不同了 , 再就是 会自动的返回新创建的对象 什么是原型?        原型的作用:就是为了实现继承!  一个对象的原型就是它的构造函数的prototype属性的值. 在讨论原型的时候,是指的 对象和原型对关系 prototyp

Resolve Type中构造函数传值

1 1 class Test 2 { 3 4 private ITeacher _teacher; 5 private IStudent _student; 6 public Test(ITeacher tea, IStudent stu) 7 { 8 _teacher = tea; 9 _student = stu; 10 } 11 } 2 1 class Student:IStudent 2 { 3 4 public Student() 5 { 6 int i = 1; 7 } 8 9 10

构造函数、拷贝构造函数、赋值操作符

对于这样一种类与类之间的关系,我们希望为其编写“深拷贝”.两个类的定义如下: class Point { int x; int y; }; class Polygon : public Shape { Point *points; }; 1. 构造函数 //构造函数 Polygon(const Point &p) : _point(new Point) { this->_point->x = p.x; this->_point->y = p.y; } 2. 拷贝构造函数 /

JAVA_SE基础——29.构造函数

黑马程序员入学Blog... jvm创建Java对象时候需要调用构造器,默认是不带参数的.在构造器中,你可以让jvm帮你初始化一些参数或者执行一系列的动作. 它是对象创建中执行的函数,及第一个被执行的方法 特点: 1.函数名与类名相同. 2.不用定义返回值类型. 3.没有具体的返回值. P.S. 在构造函数前面加上返回值就只是一般函数了. 作用:给对象进行初始化. class Person{ private String name ; private int age ; //定义一个Person

C++ 构造函数和析构函数

构造函数: 作用: 1)分配空间:分配非静态数据成员的存储空间 2)初始化成员:初始化非静态数据成员 分配空间: 1)含有指针变量,需要程序员显式申请空间(使用new申请) 2)非指针变量:由系统自动分配空间 初始化成员: 1)使用赋值语句初始化:一般的变量 2)使用表达式表初始化:一般的变量 +  Const成员,引用成员,对象成员 调用时机:在定义对象的时候,系统自动调用构造函数 1)对象被创建时,自动调用构造函数 Coord p1(1); Coord p2=1;  //此时也会调用构造函数

构造函数和析构函数是否可以被重载

构造函数可以被重载,因为构造函数可以有多个且可以带参数. 析构函数不可以被重载,因为析构函数只能有一个,且不能带参数.