前言数组
本文主要来说解一下C#中,本身以为掌握的不怎么样或者用的很少,不太熟悉的关键字,主要包括base、this、new、override、abstract、virtual以及针对static字段和static构造函数之间的执行问题。ide
base关键字函数
base 关键字用于在派生类中实现对基类公有或者受保护成员的访问,可是只局限在构造函数、实例方法和实例属性访问器中:ui
调用基类上已被其余方法重写的方法。this
public class Father { public virtual void Say() { Console.WriteLine("Father Say"); } } public class Son : Father { public override void Say() { base.Say(); Console.WriteLine("Son Say"); } }
指定建立派生类实例时应调用的基类构造函数。spa
public class Father { public string Name { get; set; } public Father() { Name = "Father"; } } public class Son : Father { public Son() : base() { } }
从静态方法中使用 base 关键字是错误的。3d
this关键字code
其用于引用类的当前实例,也包括继承而来的方法,一般能够隐藏this:对象
public class Person { public string Name { get; set; } public int Age { get; set; } public Person(string Name, int Age) { this.Name = Name; this.Age = Age; } }
public class Person { public string Name { get; set; } public int Age { get; set; } public Person(string Name, int Age) { this.Name = Name; this.Age = Age; } public void CallTest(Person person) { Console.WriteLine(person.Name+person.Age); } public void Call() { CallTest(this); } }
public class Person { string[] PersonList = new string[10]; public string this[int param] { get { return PersonList[param]; } set { PersonList[param] = value; } }
new关键字blog
1、new运算符
一、new一个class时,new完成了如下两个方面的内容:一是调用new class命令来为实例在托管堆中分配内存;二是调用构造函数来实现对象初始化。
二、new一个struct时,new运算符用于调用其带构造函数,完成实例的初始化。
三、new一个int时,new运算符用于初始化其值为0。
四、 new运算符不可重载。
五、new分配内存失败,将引起OutOfMemoryException异常。
2、new修饰符
new 关键字能够显式隐藏从基类继承的成员。 隐藏继承的成员时,该成员的派生版本将替换基类版本。 虽然能够在不使用 new 修饰符的状况下隐藏成员,但会生成警告。 若是使
用 new 显式隐藏成员,则会取消此警告,并记录要替换为派生版本这一事实。
在子类中用 new 关键字修饰 定义的与父类中同名的方法,叫覆盖。 覆盖不会改变父类方法的功能。
public class A { public virtual void Test() { Console.WriteLine("A.Test()"); } } public class B : A { public new void Test() { Console.WriteLine("B.Test()"); } } class Program { static void Main(string[] args) { A a = new A(); a.Test(); B b = new B(); b.Test(); A c = new B(); c.Test(); Console.ReadLine(); } } }
当用子类建立父类的时候,如 A c = new B(),覆盖不会改变父类的功能,仍然调用父类功能。(和override有区别,下面进行讲解)
3、new 约束
new 约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。 若是要使用 new 约束,则该类型不能为抽象类型。
当与其余约束一块儿使用时,new() 约束必须最后指定:
public class ClassA<T>where T : IComparable, new() { //// }
override关键字
要扩展或修改继承的方法、属性、索引器或事件的抽象实现或虚实现,必须使用 override 修饰符。
由 override 声明重写的方法称为重写基方法。 重写的基方法必须与 override 方法具备相同的签名。
不能重写非虚方法或静态方法。 重写的基方法必须是 virtual、abstract 或 override 的。
用关键字 virtual 修饰的方法,叫虚方法。能够在子类中用override 声明同名的方法,这叫“重写”。相应的没有用virtual修饰的方法,咱们叫它实方法。 重写会改变父类方法的功能。
public class A { public virtual void Test() { Console.WriteLine("A.Test()"); } } public class B : A { public override void Test() { Console.WriteLine("B.Test()"); } } class Program { static void Main(string[] args) { A a = new A(); a.Test(); B b = new B(); b.Test(); A c = new B(); c.Test(); Console.ReadLine(); } }
new 和override
一、 不论是重写仍是覆盖都不会影响父类自身的功能。
二、当用子类建立父类的时候,如 A c = new B(),重写会改变父类的功能,即调用子类的功能;而覆盖不会,仍然调用父类功能。
三、虚方法、实方法均可以被覆盖(new),抽象方法,接口 不能够。
四、抽象方法,接口,标记为virtual的方法能够被重写(override),实方法不能够。
五、重写使用的频率比较高,实现多态;覆盖用的频率比较低,用于对之前没法修改的类进行继承的时候。
abstract关键字
针对abstract关键字暂时总结了如下五点:
1.用关键字abstract定义的类即为抽象类,且只能做为基类,也不能被实例化。
2.用abstract定义的类不必定包含抽象方法,也能够包含非抽象方法。
3.abstract定义的方法必定包含在抽象类中。
4.抽象类不能定义为密封类(sealed),抽象方法不能使用virtual、static、private修饰符
5.若是派生类没有实现全部的抽象方法,则该派生类也必须声明为抽象类。
virtual关键字
Virtual方法(虚方法)
virtual 关键字用于在基类中修饰方法。virtual的使用会有两种状况:
状况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。
状况2:在基类中定义了virtual方法,而后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。
static字段和static构造函数
主要来讲明执行的顺序:
一、编译器在编译的时候,先分析所须要的静态字段,若是这些静态字段所在的类有静态的构造函数,那么就会忽略字段的初始化;若是没有静态的构造函数,那么就会对静态字段进行初始化。
二、若是存在多个静态类,那么初始化的静态成员的顺序会根据引用的顺序,先引用到的先进行初始化,但若是类的静态成员的初始化依赖于其余类的静态成员,则会先初始化被依赖的静态成员。
三、而带有静态构造函数的类的静态字段,只有在引用到的时候才进行初始化。
下面咱们来看两个简单的小例子:
public class A { public static int X = B.Y+1; static A() { } } public class B { public static int Y=A.X+1; } class Program { static void Main(string[] args) { Console.WriteLine("A.X={0},B.Y={1}",A.X,B.Y); Console.ReadLine(); } }
结果如何呢?再来看第二个小例子:
public class A { public static int X = B.Y+1; } public class B { public static int Y=A.X+1; static B() { } } class Program { static void Main(string[] args) { Console.WriteLine("A.X={0},B.Y={1}",A.X,B.Y); Console.ReadLine(); } }
对比一下,这两个例子,若是你想的和你执行后的结果一致,那说明你应该已经明白它们的执行顺序了。
abstract、virtual、override 和 new 是在类的继承关系中经常使用的四个修饰方法的关键字,在此略做总结。
1. 经常使用的中文名:abstract 抽象方法,virtual 虚方法,override 覆盖基类方法,new 隐藏基类方法,override 和 new 有时都叫重写基类方法。
2. 适用场合:abstract 和 virtual 用在基类(父类)中;override 和 new 用在派生类(子类)中。
3. 具体概念:
abstract 抽象方法,是空方法,没有方法体,派生类必须以 override 实现此方法。
virtual 虚方法,若但愿或预料到基类的这个方法在未来的派生类中会被重写(override 或 new),则此方法必须被声明为 virtual。
override 重写继承自基类的 virtural 方法,能够理解为拆掉老房子,在原址上建新房子,老房子再也找不到了(除非显式地用 base. 调用基类方法)。
new 隐藏继承自基类的 virtual 方法,老房子还留着,在旁边盖个新房,想住新房住新房(做为派生类对象调用),想住老房住老房(做为基类对象调用)。
当派生类中出现与基类同名的方法,而此方法前面未加 override 或 new 修饰符时,编译器会报警告,但不报错,真正执行时等同于加了 new。
4. abstract 和 virtual 的区别:abstract 方法还没实现,连累着基类也不能被实例化,除了做为一种规则或符号外没啥用;virtual 则比较好,派生类想重写就重写,不想重写就吃老子的。并且继承再好也是少用为妙,继承层次越少越好,派生类新扩展的功能越少越好,virtual 深合此意。
5. override 和 new 的区别:当派生类对象做为基类类型使用时,override 的执行派生类方法,new 的执行基类方法。若是做为派生类类型调用,则都是执行 override 或 new 以后的。
演示 override 和 new 区别的例子:
System.Console.WriteLine("----------");
}
输出相似以下所示:
Four wheels and an engine.
----------
Four wheels and an engine.
A roof that opens up.
----------
Four wheels and an engine.
Carries seven people.
----------
可是,若是咱们声明一个从 Car 基类派生的对象的数组。此数组可以存储 Car、ConvertibleCar 和 Minivan 对象,以下所示:
cars[2] = new Minivan();
}
而后用一个 foreach 循环来访问该数组中包含的每一个 Car 对象,并调用 DescribeCar 方法,以下所示:
System.Console.WriteLine("----------");
}
此循环的输出以下所示:
Car object: YourApplication.Car
Four wheels and an engine.
----------
Car object: YourApplication.ConvertibleCar
Four wheels and an engine.
----------
Car object: YourApplication.Minivan
Four wheels and an engine.
Carries seven people.
----------
注意,ConvertibleCar 的说明可能与您的预期不一样。因为使用了 new 关键字来定义此方法,所调用的不是派生类方法,而是基类方法。Minivan 对象正确地调用重写方法,并产生预期的结果。