也说new
也说new
今天看到了Anytao的[你必须知道的.NET] 第五回:深入浅出关键字---把new说透。Anytao这一系列文章写得都非常好,其实甚至正是我一直想写的。比起各种应用层面上的技巧,我更喜欢研究.NET的底层机制。但是光顾了自己研究了,也没好好写东西给大家分享。
《把new说透》这篇文章介绍的内容不错,但Anytao文字上可能没有表达得很清晰。C# 2.0中关键字new有三种作用——1)作为修饰符覆盖父类中的virtual成员,2)作为运算符创建对象,3)作为泛型类型中对类型形参的约束。
new的这三种功能其实是完全不相干的,Anders Liu个人感觉作为文章来说,应该完全分开在不同的小节中去介绍。
1 new修饰符
new修饰符用于修饰类型成员(属性、方法等)。
(懒得画图写代码了,所以采用纯文字描述。大家可以看Anytao的代码)
当父类中编写了virtual方法时,子类出现了相同签名的方法时,必须冠以override或new运算符。
如果使用override运算符,则可以实现“多态”。即:将子类对象转成父类型后,调用virtual方法,实际上执行的是子类中的方法代码。
而如果使用new运算符,则不会出现上述情况,将子类对象转成父类型后,调用virtual方法,实际上执行的是还是父类中的方法代码。
2 new运算符
new运算符用于创建对象。当使用new运算符创建对象时,会发生下列事情:
- 根据元数据中的类型信息,计算对象所需空间,根据值类型/引用类型的区别,在栈或者堆中开辟适当大小的存储区域。
- 根据元数据中的类型信息,对类成员空间进行排列。并初始化成员。(*)
- 调用构造器。
- 返回对象引用。
所以,string s = new string("asdf");实际上是首先根据string类型信息在堆上开辟存储空间,排列其成员,然后调用string(string s)签名的构造器,最后返回新对象引用,并通过等号赋给变量s。
因此,Anytao提到的int i与int i = new int()的区别也就出来了。
但这里Anytao没有陈述清楚的是,int i出现的位置——int i即可以出现在类中,成为一个字段(域);也可以出现在方法中,成为一个变量(还有一种是出现在方法参数中,但就其语义,和变量是类似的)。
如果int i是一个字段(域)定义,那么两者是没有任何区别的。因为,注意上面第二条带(*)的部分,当客户代码初始化当前类的对象时,会同时初始化这个i,将其值置为0。
如果int i是一个变量定义,那么,int i只是声明了一个局部变量,此时的i不能直接使用,必须首先赋值(如果未赋值就使用,会得到一个编译错误)。而int i = new int()则对i进行了一个初始化。
3 new约束
在泛型类型定义时,可以使用where指定一些约束,其中一种就是new约束。new 约束要求用作类型实参的类型必须带有公共无参构造器。如class A<T> where T : new();这里只有带有公共无参构造器的类型才能用作T。
需要注意两点,1)如果同时存在其他约束,那么new约束应该是最后一个。2)不能用new(int i)的形式来约束拥有指定签名的构造器。
好了,希望Anders Liu能给Anytao梳理一下文字。