前言ide
本文主要來說解一下C#中,本身以爲掌握的不怎麼樣或者用的很少,不太熟悉的關鍵字,主要包括base、this、new、override、abstract、virtual以及針對static字段和static構造函數之間的執行問題。函數
base關鍵字ui
base 關鍵字用於在派生類中實現對基類公有或者受保護成員的訪問,可是隻侷限在構造函數、實例方法和實例屬性訪問器中:this
調用基類上已被其餘方法重寫的方法。spa
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"); } }
指定建立派生類實例時應調用的基類構造函數。3d
public class Father { public string Name { get; set; } public Father() { Name = "Father"; } } public class Son : Father { public Son() : base() { } }
從靜態方法中使用 base 關鍵字是錯誤的。code
this關鍵字對象
其用於引用類的當前實例,也包括繼承而來的方法,一般能夠隱藏this:blog
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關鍵字繼承
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(); } }
對比一下,這兩個例子,若是你想的和你執行後的結果一致,那說明你應該已經明白它們的執行順序了。