我們知道在C#中,基類聲明為virtual和abstract的成員,在子類中可以被override,也就是重寫。其實被加上override關鍵字的成員,它本身也是virtual的,可以繼續被子類的成員override。
建立一個.NET Core控制台項目,敲入下面的代碼:
using System;
using System.Reflection;
namespace ConsoleApp
{
public class A
{
public virtual void SampleMethod()
{
Console.WriteLine("A.SampleMethod");
}
}
public class B : A
{
public override void SampleMethod()
{
Console.WriteLine("B.SampleMethod");
}
}
public class C : B
{
public override void SampleMethod()
{
Console.WriteLine("C.SampleMethod");
}
}
class Program
{
static void Main(string[] args)
{
A a = new C();
a.SampleMethod();
B b = new C();
b.SampleMethod();
MethodInfo methodSampleMethodInA = typeof(A).GetMethod("SampleMethod", BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine("A.SampleMethod is virtual? {0}", methodSampleMethodInA.IsVirtual.ToString());
MethodInfo methodSampleMethodInB = typeof(B).GetMethod("SampleMethod", BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine("B.SampleMethod is virtual? {0}", methodSampleMethodInB.IsVirtual.ToString());
MethodInfo methodSampleMethodInC = typeof(C).GetMethod("SampleMethod", BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine("C.SampleMethod is virtual? {0}", methodSampleMethodInC.IsVirtual.ToString());
Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}
執行上面的代碼,結果如下所示:
可以看到,我們在上面的代碼中,定義了類A,類B繼承類A,類C繼承類B。類A的SampleMethod方法是virtual的,是虛方法。類B的SampleMethod方法使用override關鍵字,重寫了類A的SampleMethod方法。類C的SampleMethod方法又使用override關鍵字,重寫了類B的SampleMethod方法。我們在Main方法中,使用A a和B b來調用SampleMethod方法時,最後都調用的是類C的SampleMethod方法,因為A a和B b指向的都是類C的對象(new C()),并且類A和類B的SampleMethod方法,在繼承鍊中最終都被類C的SampleMethod方法給重寫(override)了。是以我們可以看到實際上被聲明為override的成員,還可以繼續被子類成員使用override關鍵字重寫,這說明聲明為override的成員本身就是virtual的,我們可以從上面Main方法的代碼中看到,當使用反射來擷取類A、類B、類C的SampleMethod方法時,這三個SampleMethod方法的IsVirtual屬性都為true,這說明聲明為virtual和override的方法,都是虛方法。
但是現在如果我們在類B和類C的SampleMethod方法上,使用new關鍵字來隐藏基類的SampleMethod方法,那麼會得到完全不一樣的結果,如下代碼所示:
using System;
using System.Reflection;
namespace ConsoleApp
{
public class A
{
public virtual void SampleMethod()
{
Console.WriteLine("A.SampleMethod");
}
}
public class B : A
{
public new void SampleMethod()
{
Console.WriteLine("B.SampleMethod");
}
}
public class C : B
{
public new void SampleMethod()
{
Console.WriteLine("C.SampleMethod");
}
}
class Program
{
static void Main(string[] args)
{
A a = new C();
a.SampleMethod();
B b = new C();
b.SampleMethod();
MethodInfo methodSampleMethodInA = typeof(A).GetMethod("SampleMethod", BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine("A.SampleMethod is virtual? {0}", methodSampleMethodInA.IsVirtual.ToString());
MethodInfo methodSampleMethodInB = typeof(B).GetMethod("SampleMethod", BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine("B.SampleMethod is virtual? {0}", methodSampleMethodInB.IsVirtual.ToString());
MethodInfo methodSampleMethodInC = typeof(C).GetMethod("SampleMethod", BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine("C.SampleMethod is virtual? {0}", methodSampleMethodInC.IsVirtual.ToString());
Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}
當我們将類B和類C的SampleMethod方法,從override關鍵字改為new關鍵字後,A a調用的是類A的SampleMethod方法,B b調用的是類B的SampleMethod方法,并且類B和類C的SampleMethod方法通過反射得到的IsVirtual屬性現在為false,說明類B和類C的SampleMethod方法,現在不是虛方法了。
參考文獻:
virtual (C# Reference)
override (C# Reference)
new modifier (C# Reference)