研究C#的构造函数

我这人就爱较真儿。今天八卦一下C#的构造函数:

(一)先看一下引用类型的实例构造函数(ctor):

测试一,无参ctor:

image

只要是程序员,都这么写过代码。我们甚至可以省略B和A的无参ctor,但是,在CLR内部,会默认为B和A创建各自的默认无参ctor(啥事儿也不做),new B的时候,一级级从子孙向祖先往上冒,直到所有类的基类:Object的ctor。

当我们在Visual Studio中创建一个窗体的时候,对下面的代码是习以为常的:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
}
习惯最可怕,它会让你迷失自我,不相信?看下面的测试:
 
测试二,把B中的无参ctor修改为有参ctor:
image 
 
编译不能通过,错误如上图所示。有人说了,B不是有默认构造函数么?俄,看起来,只能由CLR内部使用哦,我们想要用,没戏。
如果想创建上述的B对象,必须这么写:
int v = 10;
B b = new B(v);
 
有人会问,B的ctor为什么不写成:
image 

就是说,为什么不用base。我说不用,因为此时A中只有一个无参ctor,所以,不管B中加不加base,都会调用A的这个无参ctor。

 
测试三,如果A中有2个ctor:
image 
这时,B的ctor仍然会调用A的默认无参ctor,不信你就debug试试。
 
如果此时B的ctor是有参的,仍然会调用A的默认无参ctor,谁叫你不给B的ctor加base的呢:
image 
 
最后介绍最正规的做法:
image 
 
说到底,就是默认构造函数的有无在作祟,没啥道理可言,因为都是C# Team制定的规则,如果不小心写错了,编译器第一个会报错,所以不怕工作中出错,也就面试的时候会被搞死。
 

(二)然后恶搞值类型的实例构造函数(ctor),说实话,我很烦它,胜过static类,因为从来没有在项目中自定义过struct,但是每次总结C#语法,它和static都是特例。但static类我起码在Silverlight中Command中经常写。

测试一:

image

这么玩的结果就是,struct中所有的成员都是0或null,可是这样的对象,我们真的需要吗?

所以,接下来,你还要手动设置struct中的各个属性:

SomeValueType b = new SomeValueType() { y = 2 };
b.x = 1;

娃哈哈,struct居然支持C# 3.0新语法,刮目一个。

此外,你还会发现,struct中也可以有引用类型的成员,没见过这么玩的吧?反正我做了5年也没见过哪个项目这么搞。

测试二:

如果你要使用struct的无参ctor,千万别在struct中声明无参ctor,不信你就试试,如下所示:

image 

测试三:

看来还是做一个有参数的ctor比较靠谱:

image

但是,struct中所有的变量,都要在有参ctor中进行初始化,不信那个邪,少一个就搞死你,如下所示:

image

测试四:

你要是敢这么写:

image

就相当于没看懂我这篇文章,请 goto 测试一。

(三)最后,yy一下类的ctor。我习惯称其为cctor。

cctor只允许存在一个无参cctor,而且还不能带有访问修饰符(例如private),默认为private的(但就是不让你指定private):

image

说白了,cctor就是用来实例化类中那些静态成员的。而且是一次性的,仅在类创建(new)的时候(而不是声明的时候)执行。

调试上面的例子,我们会发现,a先等于1,后等于3,这说明static内联赋值要比cctor还要早。

话说,cctor可以用于引用类型/值类型,但在值类型中定义cctor是没有意义的。看过上文就会知道,值类型是没有机会执行cctor的。

cctor的调用过程如下:
    编译时,JIT编译器将检查AppDomain是否执行了cctor(有记录的),以决定是否生成调用代码;
    执行时,如果有多个线程,则需要一个互斥的线程同步锁,以确保只执行一次cctor。


cctor位于AppDomain中,因此不支持静态的Finalize()方法,就是说对GC免疫。

cctor不会调用其基类的cctor,两者是没有关系的。

本来cctor是非常简单的,但和“实例”混在一起的时候,就很容易混淆了。

静态变量和实例变量并不是一对反义词。

1)实例方法中可以使用静态成员/方法。

2)静态方法中不能使用定义在该静态方法外的实例成员

3)但在静态方法中,可以使用定义在该静态方法内的实例成员

4)永远的特例——Main函数

class A
{
    private static int a = 1;

    static A()
    {
        a = 3;
    }

    public string b = "bjq";

    public A()
    {
        a = 2;
    }

    static void Main(string[] args)
    {
        Console.WriteLine(a); 
    }
}
原文地址:https://www.cnblogs.com/Jax/p/1601897.html