笔记05 局部类型
C# 2.0 引入了局部类型的概念。局部类型允许我们将一个类、结构或接口分成几个部分,分别实现在几个不同的.cs文件中。
局部类型适用于以下情况:
(1) 类型特别大,不宜放在一个文件中实现。
(2) 一个类型中的一部分代码为自动化工具生成的代码,不宜与我们自己编写的代码混合在一起。
(3) 需要多人合作编写一个类。
局部类型是一个纯语言层的编译处理,不影响任何执行机制——事实上C#编译器在编译的时候仍会将各个部分的局部类型合并成一个完整的类。
{
static void Main(string[] args)
{
}
}
partial class Program
{
public void Test()
{
}
}
2. 局部类型的限制
(1) 局部类型只适用于类、接口、结构,不支持委托和枚举。
(2) 同一个类型的各个部分必须都有修饰符 partial。
(3) 使用局部类型时,一个类型的各个部分必须位于相同的命名空间中。
(4) 一个类型的各个部分必须被同时编译。
3. 局部类型的注意点
(1) 关键字partial是一个上下文关键字,只有和 class、struct、interface 放在一起时才有关键字的含义。因此partial的引入不会影响现有代码中名称为partial的变量。
(2) 局部类型的各个部分一般是分开放在几个不同的.cs文件中,但C#编译器允许我们将他们放在同一文件中。
4. 局部类型的应用特性
在局部类型上的特性具有“累加”效应。
partial class Class1{}
[Attribute3, Attribute2("Exit")]
partial class Class1{}
相当于
class Class1 {}
注:Attribute2属性允许在类上多次使用。
5. 局部类型上的修饰符
(1) 一个类型的各个部分上的访问修饰符必须维持一致性。
(2) 如果一个部分类使用了abstract修饰符,那么整个类都将被视为抽象类。
(3) 如果一个部分类使用了 sealed 修饰符,那么整个类都将被视为密封类。
(4) 一个类的各个部分不能使用相互矛盾的修饰符,比如不能在一个部分上使用abstract,又在另一个部分上使用sealed。
(5)如果一个部分类使用了 static修饰符,那么整个类都将被视为静态类。
6. 局部类型的基类和接口
(1) 一个类型的各个部分上指定的基类必须一致。某个部分可以不指定基类,但如果指定,则必须相同。
(2) 局部类型上的接口具有“累加”效应。
partial class Class2: Iinterface3 {}
partial class Class2: Iinterface2 {}
Virtual :
virtual 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。
默认情况下,方法是非虚拟的。不能重写非虚方法。
virtual 修饰符不能与 static、abstract, private 或 override 修饰符一起使用。
Override :
override 方法提供从基类继承的成员的新实现。
由 override 声明重写的方法称为重写基方法。重写的基方法必须与 override 方法具有相同的签名。
重写的基方法必须是vitural,override,abstract类型的 ,不能重写非虚方法或是静态方法。
所以override不能与vitural,new,static同时使用。
override 属性,声明必须指定与继承属性完全相同的访问修饰符、类型和名称,并且被重写的属性必须是 virtual、abstract 或 override 的。(注意:这里是属性,不是字段,字段是不能被重写的)。
New :
用于创建对象和调用构造函数。
使用 new 修饰符可以显式隐藏从基类继承的成员。
若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new 修饰符修饰它。
下面用代码来说明:
- //By Alan Liao 2008-10-22
- class Father
- {
- protected string firstname;
- protected string lastname;
- public Father()
- {
- }
- public Father(string firstname, string lastname)
- {
- this.firstname = firstname;
- this.lastname = lastname;
- }
- public virtual void GetFullName()
- {
- Console.WriteLine("Father:{0} {1}", firstname, lastname);
- }
- }
- class Son : Father
- {
- public int age;
- public Son() : base() { }
- public Son(string firstname, string lastname,int age):base(firstname,lastname)
- {
- this.age = age;
- }
- //public new void GetFullName()
- public override void GetFullName()
- {
- Console.WriteLine("Son:{0} {1}", firstname, lastname);
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- Father father = new Father("Alan", "Liao");
- Father son1 = new Son("Little Alan ", "Liao",20);
- father.GetFullName();
- son1.GetFullName();
- Console.ReadLine();
- }
- }
本代码输出:
Father:Alan Liao
Son:Little Alan Liao
若将36行换成35行(即将Override换成New)
输出结果为:
(其实代码中的virtual,override 都可以去掉,可以编译,运行通过,但是会有Warnning,结果同下)
Father:Alan Liao
Father:Little Alan Liao
可见结果不一样。
Father a=new Son();
使用new声明的方法使用的仍是父类方法,而override声明的方法使用的是子类中的方法。
其实,根本原因是对象a会优先调用子类中的方法,如果子类没有重写父类的方法,a 就调用父类中的方法。
override 说明的是虚方法,在子类中覆盖父类中的方法。
new则不是,new是给子类新增加了一个函数,可以说除了函数名字相同以外,它跟基类里面的这个同名函数没有任何关系。相当于重新新建了一个方法,从而隐藏了父类方法.
其它:
在 C# 中,派生类可以包含与基类方法同名的方法。
(1)基类方法必须定义为 virtual。
(2)如果派生类中的方法前面没有 new 或 override 关键字,则编译器将发出警告,
该方法将有如存在 new 关键字一样执行操作。
(3)如果派生类中的方法前面带有 new 关键字,则该方法被定义为独立于基类中的方法。
(4)如果派生类中的方法前面带有 override 关键字,则派生类的对象将调用该方法,而不是调用基类方法。
(5)可以从派生类中使用 base 关键字调用基类方法。
(6) override、virtual 和 new 关键字还可以用于属性、索引器和事件中。
补充:
- class Father
- {
- public virtual void PrintName()
- {
- Console.WriteLine("Father:{0}", this.GetType().ToString());
- }
- }
- class Son : Father
- {
- //public new void PrintName()
- public override void PrintName()
- {
- Console.WriteLine("Son:{0}", this.GetType().ToString());
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- Father father = new Father();
- Father son = new Son();
- father.PrintName();
- son.PrintName();
- Console.ReadLine();
- }
- }
以上程序的运行结果:(其中myNamespace是这两个类的命名空间)
Father:myNamespace.Father
Son:myNamespace.Son
如果在第11行将override换成new,那么运行结果如下:
Father:myNamespace.Father
Father:myNamespace.Son
从上可以看出虽然调用的是Father类中的方法,但是this.GetType()返回的是myNamespace.Son类型,所以在Father中的PrintName()方法中的this指的是调用该方法的对象,而不是定义该方法的对象
当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承。类似于Java中final关键字。
在下面的示例中,类 B 从类 A 继承,但是任何类都不能从类 B 继承。
2. sealed 修饰方法或属性
能够允许类从基类继承,并防止它们重写特定的虚方法或虚属性。
1)sealed是对虚方法或虚属性,也就是同override一起使用,如果不是虚方法或虚属性会报出错误:cannot be sealed because it is not an override
- public class D
- {
- /* ConsoleApplication1.MSFun.Sealed.D.M()'
- * cannot be sealed because it is not an override
- */
- public sealed void M() { Console.WriteLine("D.M()"); }
- }
- public class A
- {
- protected virtual void M() { Console.WriteLine("A.M()"); }
- protected virtual void M1() { Console.WriteLine("A.M1()"); }
- }
- public class B : A
- {
- protected sealed override void M() { Console.WriteLine("B.M()"); }
- protected override void M1() { Console.WriteLine("B.M1()"); }
- }
- public sealed class C : B
- {
- /* ConsoleApplication1.MSFun.Sealed.C.M()':
- * cannot override inherited member 'ConsoleApplication1.MSFun.Sealed.B.M()'
- * because it is sealed */
- //protected override void M() { Console.WriteLine("C.M()"); }
- protected override void M1() { Console.WriteLine("C.M1()"); }
- }