C#類中方法的執行順序
有些中級開發小夥伴還是搞不太明白在繼承父類以及不同場景實例化的情況下,父類和子類的各種方法的執行順序到底是什麼,下面通過場景的舉例來重新認識下方法的執行順序:
(下面內容涉及到了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()方法,故運行結果為:
場景二
實例化子類,子類和父類的構造函數的執行順序:當執行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(),故運行結果為:
場景三
父類有虛方法,子類沒有使用(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()方法(沒有重寫父類方法),故運行結果為:
場景四
父類有虛方法, 當子類重寫了(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關鍵字),所以其運行結果為:
場景五
基類是介面層,多重繼承時:
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();
}
列印結果:
場景六
當多重繼承,子類重寫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)
場景七
使用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();
}
列印結果: