C#基礎知識(base、this、new、override、abstract、virtual、static)

前言數組

本文主要來說解一下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 區別的例子:

 

複製代碼

// Define the base class
class Car
{
   public virtual void DescribeCar()
   {
       System.Console.WriteLine("Four wheels and an engine.");
   }
}

// Define the derived classes
class ConvertibleCar : Car
{
   public new virtual void DescribeCar()
   {
       base.DescribeCar();
       System.Console.WriteLine("A roof that opens up.");
   }
}
class Minivan : Car
{
   public override void DescribeCar()
   {
       base.DescribeCar();
       System.Console.WriteLine("Carries seven people.");
   }
}
public static void TestCars1()
{
   Car car1 = new Car();
   car1.DescribeCar();
   System.Console.WriteLine("----------");

   ConvertibleCar car2 = new ConvertibleCar();
   car2.DescribeCar();
   System.Console.WriteLine("----------");

   Minivan car3 = new Minivan();
   car3.DescribeCar();

   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 對象,以下所示:

 

複製代碼

public static void TestCars2()
{
    Car[] cars = new Car[3];
    cars[0] = new Car();
    cars[1] = new ConvertibleCar();

    cars[2] = new Minivan();

}

複製代碼

 

而後用一個 foreach 循環來訪問該數組中包含的每一個 Car 對象,並調用 DescribeCar 方法,以下所示:

 

複製代碼

foreach (Car vehicle in cars)
{
  System.Console.WriteLine("Car object: " + vehicle.GetType());
  vehicle.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 對象正確地調用重寫方法,併產生預期的結果。

相關文章
相關標籤/搜索