2017年9月2日 星期六

.NET C# 類別繼承 Class Inheritance 中的建構函式 Constructor 執行順序

在這份筆記之中,我們要來檢測類別繼承的架構下,這些被繼承的建構式的執行順序。

了解更多關於 [C# 和 .NET 中的繼承的使用方式
了解更多關於 [C# 程式設計手冊 
了解更多關於 [建構函式



測設的類別宣告與測試程式

底下列出了我們這測試的三種不同建立類別的情境會用到的 C# 原始碼
namespace ConsoleApp2
{
    /// <summary>
    /// 祖父級的基礎類別
    /// </summary>
    public class BaseBaseClass
    {
        public BaseBaseClass()
        {
            Console.WriteLine("Call BaseBaseClass() Constructor");
        }
    }

    /// <summary>
    /// 父親級的基礎類別
    /// </summary>
    public class BaseClass : BaseBaseClass
    {
        public BaseClass()
        {
            Console.WriteLine("Call BaseClass() Constructor");
        }
        public BaseClass(string para)
        {
            Console.WriteLine($"Call BaseClass(\"{para}\") Constructor");
        }
    }

    /// <summary>
    /// 衍生類別
    /// </summary>
    public class DerivedClass : BaseClass
    {
        public DerivedClass()
        {
            Console.WriteLine("Call DerivedClass() Constructor");
        }
        public DerivedClass(string para)
        {
            Console.WriteLine($"Call DerivedClass(\"{para}\") Constructor");
        }
        public DerivedClass(string para, int paraInt):base(para)
        {
            Console.WriteLine($"Call DerivedClass(\"{para}\", \"{paraInt}\") Constructor");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("測試一 new DerivedClass()");
            var fooDerivedClassObject = new DerivedClass();
            Console.WriteLine("---------------");
            Console.WriteLine("測試二 new DerivedClass(some string)");
            var fooDerivedClassObjectWithArg = new DerivedClass("Create Derived Class with Argument");
            Console.WriteLine("---------------");
            Console.WriteLine("測試三 new DerivedClass(some string, some int)");
            var fooDerivedClassObjectWith2Arg = new DerivedClass("Create Derived Class with Argument", 2);
            Console.WriteLine("Press any key for continuing...");
            Console.ReadKey();
        }
    }
}

類別繼承架構與建構式設計說明

在這裡,我們定義了三個類別
  • BaseBaseClass
    這個類別是在繼承關係中,位於最上層的位置,也就是所有類別的祖先,我在這裡簡稱為 基礎基礎類別
    在這裡類別中,只有預設建構式,為了要能夠知道程式執行過程中,有呼叫到這個 基礎基礎類別 的建構式,所以,我還是把這個預設建構是寫了出來,不過,裡面只有輸出一段訊息到命令提示視窗中。
        public BaseBaseClass()
        {
            Console.WriteLine("Call BaseBaseClass() Constructor");
        }
  • BaseClass
    這個類別,繼承了 BaseBaseClass (基礎基礎類別) ,在這我稱它為 基礎類別
    在這個基礎類別中,我們定義了兩個建構式,一個是預設建構式,另外一個建構式會接收一個字串參數。會設計這兩個建構式,主要是要測試,當衍生類別沒有特別指定基礎類別要執行的建構式的時候,在基礎類別中,預設建構式會被主動的執行;若在衍生類別的建構式中,有特別指定呼叫的基礎類別的建構式,此時,該基礎類別上的指定符合函式簽章的建構式,就會被執行。
        public BaseClass()
        {
            Console.WriteLine("Call BaseClass() Constructor");
        }
        public BaseClass(string para)
        {
            Console.WriteLine($"Call BaseClass(\"{para}\") Constructor");
        }
  • DerivedClass
    這個類別,繼承了 BaseClass (基礎類別),在這裡我稱它為衍生類別
    在最後的衍生類別中,共宣告了三個種函式簽章的建構式。
        public DerivedClass()
        {
            Console.WriteLine("Call DerivedClass() Constructor");
        }
        public DerivedClass(string para)
        {
            Console.WriteLine($"Call DerivedClass(\"{para}\") Constructor");
        }
        public DerivedClass(string para, int paraInt):base(para)
        {
            Console.WriteLine($"Call DerivedClass(\"{para}\", \"{paraInt}\") Constructor");
        }

建立一個衍生類別的物件,但使用預設建構式

在這個測試中,我們使用了
            var fooDerivedClassObject = new DerivedClass();
這個敘述,建立了一個衍生類別 DerivedClass 的物件,此時,在命令提示視窗中會出現底下的訊息。
我底下的訊息中,我們可以得知,
  • 當衍生類別的物件被產生的時候,會先呼叫基礎基礎類別的建構式,因為,沒有特別指定要執行哪個基礎基礎類別的建構式,所以,基礎基礎類別的預設建構式 (BaseBaseClass())會先被執行。
  • 接著,將會呼叫基礎類別的建構式,因為,沒有特別指定要執行哪個基礎類別的建構式,所以,基礎類別的預設建構式 (BaseClass()) 會先被執行。
  • 最後,才是衍生類別的建構式 (DerivedClass()) 會被執行

執行結果

測試一 new DerivedClass()
Call BaseBaseClass() Constructor
Call BaseClass() Constructor
Call DerivedClass() Constructor

建立一個衍生類別的物件,但使用有字串參數的建構式

在這個測試中,我們使用了,也就是說,當我們要建立一個衍生類別物件的時候,順便將一個字串傳遞到建構式內,當然,我們在這個衍生類別中,就需要宣告多的建構式,並且使用不同的函式簽章,透過多載 (Overloading) 的技術,可以讓使用者選擇不同的建構式函式來建立該類別的物件。
var fooDerivedClassObjectWithArg = new DerivedClass("Create Derived Class with Argument");
在這個建構式 DerivedClass(string para) 中,我僅在呼叫衍生類別的建構式時候,輸出不同的文字內容,而基礎類別與基礎基礎類別,則會延續上個說明程序來執行。
        public DerivedClass(string para)
        {
            Console.WriteLine($"Call DerivedClass(\"{para}\") Constructor");
        }

執行結果

測試二 new DerivedClass(some string)
Call BaseBaseClass() Constructor
Call BaseClass() Constructor
Call DerivedClass("Create Derived Class with Argument") Constructor

建立一個衍生類別的物件,指定基礎類別要執行建構式函式

在這個測試中,我們將會在衍生類別的建構適中,指定要執行的基礎類別建構式,底下是我們要建立衍生類別物件的執行程式,在這裡,我們呼叫的衍生類別建構式,需要傳遞一個字串與整數進去。
            var fooDerivedClassObjectWith2Arg = new DerivedClass("Create Derived Class with Argument", 2);
在這個衍生類別建構式 DerivedClass(string para, int paraInt) 中,您可以看到,我們有使用了 :base(para) 敘述,指名要執行基礎類別的這個有接收字串參數的建構式。
因此,您可以從下方看到繼承關係的各類別之建構式的執行情況。
        public DerivedClass(string para, int paraInt):base(para)
        {
            Console.WriteLine($"Call DerivedClass(\"{para}\", \"{paraInt}\") Constructor");
        }


執行結果

測試三 new DerivedClass(some string, some int)
Call BaseBaseClass() Constructor
Call BaseClass("Create Derived Class with Argument") Constructor
Call DerivedClass("Create Derived Class with Argument", "2") Constructor


了解更多關於 [C# 和 .NET 中的繼承的使用方式
了解更多關於 [C# 程式設計手冊 
了解更多關於 [建構函式




沒有留言:

張貼留言