c# base和this的區別(base、this、virtual、override、static詳解)
今天的程式除錯中出現了以下錯誤,引發了我對base關鍵字的用法的疑惑,總結一下。
1、base關鍵字
用法1:
base是為了實現子類的方法中實現父類原有的方法。
this關鍵字代表本類物件,base關鍵字代表父類物件。
如:
base.property;//呼叫父類的屬性
base.method();//呼叫父類的方法
以下例項演示了派生類中呼叫用基類的方法,注意virtual、override關鍵詞的使用。
(1)virtual關鍵字用於修改方法、屬性、索引器或事件宣告,並使它們可以在派生類派生類中被重寫。注意靜態屬性上使用virtual關鍵字時錯誤的。
(2)override關鍵詞用於擴充套件或修改繼承的方法、屬性、索引器或事件的抽象實現或虛實現。
public class Person //父類 { protected string ssn = "444-55-6666"; protected string name = "John L. Malgraine"; public virtual void GetInfo() { Console.WriteLine("Name: {0}", name); Console.WriteLine("SSN: {0}", ssn); } } class Employee : Person //派生類 { public string id = "ABC567EFG"; public override void GetInfo() { // Calling the base class GetInfo method: base.GetInfo(); Console.WriteLine("Employee ID: {0}", id); } } class TestClass { static void Main() { Employee E = new Employee(); E.GetInfo(); } } /* Output Name: John L. Malgraine SSN: 444-55-6666 Employee ID: ABC567EFG */
注意:訪問父類(基類)成員只能在建構函式、例項方法或例項屬性中進行,因此,從靜態方法中使用base關鍵是錯誤的。我以上錯誤的原因就是因為靜態方法中使用了base。
用法2:base關鍵字還可以指定建立派生類例項時應呼叫的基類的建構函式。
public class BaseClass //父類 { int num; public BaseClass() //建構函式 { Console.WriteLine("in BaseClass()"); } public BaseClass(int i) //建構函式 { num = i; Console.WriteLine("in BaseClass(int i)"); } public int GetNum() { return num; } } public class DerivedClass : BaseClass //派生類 { // This constructor will call BaseClass.BaseClass() public DerivedClass() : base() //派生類的建構函式呼叫基類的建構函式 { } // This constructor will call BaseClass.BaseClass(int i) public DerivedClass(int i) : base(i) //派生類的建構函式呼叫基類的建構函式 { } static void Main() { DerivedClass md = new DerivedClass(); DerivedClass md1 = new DerivedClass(1); } } /* Output: in BaseClass() in BaseClass(int i) */
2、this關鍵字
用法1:
this代表當前類的例項物件
namespace Demo
{
public class Test
{
private string scope = "全域性變數";
public string getResult()
{
string scope = "區域性變數";
// this代表Test的例項物件
// 所以this.scope對應的是全域性變數
// scope對應的是getResult方法內的區域性變數
return this.scope + "-" + scope;
}
}
class Program
{
static void Main(string[] args)
{
try
{
Test test = new Test();
Console.WriteLine(test.getResult());
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
Console.ReadLine();
}
}
}
}
用法2:this串聯建構函式
namespace Demo
{
public class Test
{
public Test()
{
Console.WriteLine("無參建構函式");
}
// this()對應無參構造方法Test()
// 先執行Test(),後執行Test(string text)
public Test(string text) : this()
{
Console.WriteLine(text);
Console.WriteLine("有參建構函式");
}
}
class Program
{
static void Main(string[] args)
{
try
{
Test test = new Test("張三");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
Console.ReadLine();
}
}
}
}
3、 static關鍵字
使用 static 修飾符宣告屬於型別本身而不是屬於特定物件的靜態成員。static 修飾符可用於類、欄位、方法、屬性、運算子、事件和建構函式,但不能用於索引器、解構函式或類以外的型別。
靜態方法與非靜態方法
a、靜態方法的呼叫
類.靜態方法名([引數列表])
非靜態方法的呼叫
類 物件 = new 類的建構函式([引數列表])
物件.非靜態方法名([引數列表])
靜態方法是屬於類的,而非靜態方法是屬於物件的;
b、記憶體的初始化
靜態成員是在第一次使用時進行初始化。非靜態的成員是在建立物件的時候。
靜態建構函式只能被執行一次;非靜態的建構函式可以根據需要進行多次使用。
c、記憶體中儲存
靜態的只有一塊全域性記憶體空間,非靜態的可以有多塊記憶體空間(副本)
d、釋放
靜態的一旦建立則在全域性區一直存放,直到應用程式結束。非靜態的則是由new關鍵字在堆中建立的。可以有多個副本。由GC進行釋放。
注意:
(1)static變數及方法不用例項化物件就可以用類名.靜態變數和類名.靜態方法這種方式進行訪問,這使得訪問更加方便,不用手工例項化物件。對於某些只讀變數和方法來說很適合共享。
(2)static與非static最大的區別就是static型別的變數及方法在呼叫的時候就在記憶體中分配了地址,且這個地址只有一份,故static可以直接訪問。而非static必需手工去例項化該類,以物件的方式去訪問變數和方法。
(3)在一個靜態方法裡去訪問該類的非靜態變數或方法,由於static是屬於類本身的,是在類被呼叫的時候,static型別就已經生成,而非static此時並沒有生成,它不屬於這個類本身,它是屬於這個類的物件。故在沒有例項化成物件的時候,在靜態方法中訪問非靜態是根本找不到它們的,它不屬於這個類。
(4)在非靜態方法中去訪問靜態,由於類被呼叫時,靜態變數和方法就已經生成,也就是說它們屬於這個類。既然已經存在,故不管是在靜態方法中,還是非靜態方法中都可以訪問到它們。
(5)this表明物件本身,而在靜態方法中並沒有物件概念存在,它只有類本身這個概念,它和物件是屬於兩種互拆的狀態,即我中無你,你中無我的情況。也就是說你用物件名.靜態變數或物件名.靜態方法是不可訪問的。
(6)每個類都必須有建構函式,否則此類無法例項化成物件。而我們有時定義的類可以不寫它的建構函式,這是因為編譯器會幫我們加上一個靜態的空建構函式。這樣才能例項化。也可以用靜態建構函式去初始化靜態變數。