1. 程式人生 > >c# base和this的區別(base、this、virtual、override、static詳解)

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)每個類都必須有建構函式,否則此類無法例項化成物件。而我們有時定義的類可以不寫它的建構函式,這是因為編譯器會幫我們加上一個靜態的空建構函式。這樣才能例項化。也可以用靜態建構函式去初始化靜態變數。