Skip to content

C# 组件版本控制 new & virtual + override

🏷️ C#

先看一下三个 C# 关键字对组件版本控制的影响:

  • virtual:表示这个成员可由派生类型重写

  • override:表示派生类型正在重写基类型的成员

  • new:应用于嵌套类型、方法、属性、事件、常量或字段时,表示该成员与基类中的同名成员无任何关系

示例代码如下:

csharp
using System;

namespace VersionControlSample
{
    class Program
    {
        static void Main(string args)
        {
            CompanyB.BetterPhone phone = new CompanyB.BetterPhone();
            phone.Dial();
            Console.ReadLine();
        }
    }
}

namespace CompanyA
{
    class Phone
    {
        public void Dial()
        {
            Console.WriteLine("Phone.Dial");
        }
    }
}

namespace CompanyB
{
    class BetterPhone : CompanyA.Phone
    {
        public void Dial()
        {
            Console.WriteLine("BetterPhone.Dial");
            base.Dial();
        }
    }
}

这样写编译会出如下警告:

CompanyB.BetterPhone.Dial()”隐藏了继承的成员“CompanyA.Phone.Dial()”。如果是有意隐藏,请使用关键字 new

BetterPhone.Dial 方法添加 new 关键字,警告就消除了。

csharp
class BetterPhone : CompanyA.Phone
{
    public new void Dial()
    {
        Console.WriteLine("BetterPhone.Dial");
        base.Dial();
    }
}

执行结果为:

BetterPhone.Dial
Phone.Dial

看到这里感觉 new 关键字和使用 virtual + override 的功能类似,新的 Dial 方法替代了基类的 Dial 方法,但其实两者有着本质的区别。

  • new 关键字是用来表示该成员(这里是 BetterPhone.Dial 方法)与基类中同名成员无任何关系;

  • override 关键字则是重写基类中同名成员。

在基类 Phone 中加一个虚方法,BetterPhone 中重写该方法。修改后代码如下:

csharp
namespace CompanyA
{
    class Phone
    {
        public void Dial()
        {
            Console.WriteLine("Phone.Dial");
            EstablishConnection();
        }

        protected virtual void EstablishConnection()
        {
            Console.WriteLine("Phone.EstablishConnection");
        }
    }
}

namespace CompanyB
{
    class BetterPhone : CompanyA.Phone
    {
        public new void Dial()
        {
            Console.WriteLine("BetterPhone.Dial");
            EstablishConnection();
            base.Dial();
        }

        protected override void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
        }
    }
}

执行结果为:

BetterPhone.Dial
BetterPhone.EstablishConnection
Phone.Dial
BetterPhone.EstablishConnection

可以看到 Phone.EstablishConnection 已经被重写了,即使在 Phone.Dial 中调用的也是 BetterPhone.EstablishConnection 方法.

将上面的 override 改成 new virtual ,下面是修改后的代码:

csharp
namespace CompanyB
{
    class BetterPhone : CompanyA.Phone
    {
        public new void Dial()
        {
            Console.WriteLine("BetterPhone.Dial");
            EstablishConnection();
            base.Dial();
        }

        protected new virtual void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
        }
    }
}

执行结果为:

BetterPhone.Dial
BetterPhone.EstablishConnection
Phone.Dial
Phone.EstablishConnection

第四行的输出变成【Phone.EstablishConnection】了,说明调用了基类中的 EstablishConnection 方法。