天天看點

在C#中,override的成員仍然是virtual的

我們知道在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();
        }
    }
}      

執行上面的代碼,結果如下所示:

在C#中,override的成員仍然是virtual的

可以看到,我們在上面的代碼中,定義了類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();
        }
    }
}      
在C#中,override的成員仍然是virtual的

當我們将類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)