C#類中方法的執行順序

犁痕發表於2021-05-25

有些中級開發小夥伴還是搞不太明白在繼承父類以及不同場景例項化的情況下,父類和子類的各種方法的執行順序到底是什麼,下面通過場景的舉例來重新認識下方法的執行順序:

(下面內容涉及到了C#中的繼承,建構函式,虛方法,虛方法的重寫,new關鍵字等知識點)

場景一

有子類繼承,但是隻例項化父類:只執行A物件,輸出A物件的資訊

class A
{     
    public A() => Console.WriteLine("A的建構函式");    
    public virtual void Fun() => Console.WriteLine("A的方法");    
}
class B : A
{
    public B() => Console.WriteLine("B的建構函式");    
    public void Fun() => Console.WriteLine("B的方法");    
}
class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        a.Fun();
        Console.ReadLine();
    }
}

上述Main方法中在new A物件時,程式首先進入class A中,執行class A的建構函式A(),然後執行class A中的Fun()方法,故執行結果為:
image

場景二

例項化子類,子類和父類的建構函式的執行順序:當執行B物件時,因為繼承A物件,所以首先執行基類A的建構函式

class A
{   
    public A() => Console.WriteLine("A的建構函式");    
    public virtual void Fun()=>  Console.WriteLine("A的方法");    
}
class B : A
{
    public B() => Console.WriteLine("B的建構函式");   
    public void Fun() => Console.WriteLine("B的方法");    
}
class Program
{
    static void Main(string[] args)
    {
        B b = new B(); 
        b.Fun();
        Console.ReadKey();
    }
}

上述Main方法中在new B物件時,由於B繼承A,先執行父類的建構函式,所以先執行A中的建構函式A(),然後在執行B中的建構函式B(),故執行結果為:
image

場景三

父類有虛方法,子類沒有使用(override)關鍵字重寫父類方法的時候,使用的是new關鍵字時:

class A
{   
    public A()=>  Console.WriteLine("A的建構函式");   
    public virtual void Fun() => Console.WriteLine("A的方法");
    
}
class B : A
{
    public B() => Console.WriteLine("B的建構函式");    
    //不寫new時,該方法會丟擲警告,但不是錯誤
    public new void Fun()=> Console.WriteLine("B的方法");    
}
class Program
{
    static void Main(string[] args)
    {
        A a = new B();
        a.Fun();
        Console.ReadKey();
    }
}

上述Main方法中先new B物件,先執行A中的建構函式A(),然後在執行B中的建構函式B(),最後呼叫class A的Fun()方法(沒有重寫父類方法),故執行結果為:
image

場景四

父類有虛方法, 當子類重寫了(override)父類的方法時:

class A
{
    public A()=> Console.WriteLine("A的建構函式");    
    public virtual void Fun() =>  Console.WriteLine("A的方法");    
}
class B : A
{
    public B()=> Console.WriteLine("B的建構函式");    
    public override void Fun()=> Console.WriteLine("B的方法");    
}
static void Main(string[] args)
{
    A a = new B();
    a.Fun();
    Console.ReadKey();
}

上述Main方法同樣是先new B物件,先執行A中的建構函式A(),然後在執行B中的建構函式B(),但是子方法中使用了override關鍵字“覆蓋”,使得子類中方法覆蓋了父類中的方法,無法再訪問父類中原始方法。(要重寫方法,父類方法必須有virtual關鍵字),所以其執行結果為:
image

場景五

基類是介面層,多重繼承時:

interface I
{
    void Fun();
}
class A : I
{
    public A() => Console.WriteLine("A的建構函式");
    public virtual void Fun() => Console.WriteLine("A的方法");
}
class B : A
{
    public B() => Console.WriteLine("B的建構函式");
    //不寫new時,該方法會丟擲警告
    public new void Fun() =>Console.WriteLine("B的方法");   
}
static void Main(string[] args)
{
    B b = new B();
    b.Fun();
    ((A)b).Fun();
    ((I)b).Fun();
    Console.ReadKey();
}

列印結果:
image

場景六

當多重繼承,子類重寫override父類方法時:

interface I
{
    void Fun();
}

class A : I
{
    public A() => Console.WriteLine("A的建構函式");
    public virtual void Fun() => Console.WriteLine("A的方法");

}
class B : A
{
    public B() => Console.WriteLine("B的建構函式");    
    public override void Fun() =>Console.WriteLine("B的方法");   
}
static void Main(string[] args)
{
    B b = new B();
    b.Fun();
    ((A)b).Fun();
    ((I)b).Fun();
    Console.ReadKey();
}

列印結果:(對比場景5)
image

場景七

使用new重寫父類方法,同時讓每個子類都繼承介面:

interface I
{
    void Fun();
}

class A : I
{
    public A() => Console.WriteLine("A的建構函式");
    public virtual void Fun() => Console.WriteLine("A的方法");

}
class B : A, I
{
    public B() => Console.WriteLine("B的建構函式");
    //不寫new時,該方法會丟擲警告
    public new void Fun() => Console.WriteLine("B的方法");
}
static void Main(string[] args)
{
    B b = new B();
    b.Fun();
    ((A)b).Fun();
    ((I)b).Fun();
    Console.ReadKey();
}

列印結果:
image

相關文章