zoukankan      html  css  js  c++  java
  • 研究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); 
        }
    }
  • 相关阅读:
    面试题库
    集合的交、查、并
    mysql_server安装
    maven构建jar包
    Centos7下 升级php5.4到7.1 yum安装
    redis
    常见shell用法
    Mac下的LDAP客户端 ApacheDirectoryStudio
    redis弱密码漏洞利用
    Freeradius+Cisco2500AC+OpenLdap认证
  • 原文地址:https://www.cnblogs.com/Jax/p/1601897.html
Copyright © 2011-2022 走看看