CLR via C#学习笔记-第六章-对类型进行版本控制时的虚方法的处理

6.6.3 对类型进行版本控制时的虚方法的处理

如果类型要作为基类型使用,增加或修改它的成员时务必非常小心。

隐藏基类的同名实例方法

假定CompanyA定义了Phone类型

namespace CompanyA
{
    public class Phone
    {
        public void Dial
        {
            Console.WriteLine("Phone.Dial");
            //在这里执行拨号操作
        }
    }
}

再假定CompanyB定义了BetterPhone类型,使用CompanyA的Phone类型作为基类型

namespace CompanyB
{
    public class BetterPhone:CompanyA.Phone
    {
        public void Dial
        {
            Console.WriteLine("BetterPhone.Dial");
            EstablishConnection();
            base.Dial();
        }
        protected virtual void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
            //在这里执行建立连接的操作
        }
    }
}

CompanyB编译上述代码时,C#编译器生成以下警告消息:

warning CS0108:"CompanyB.BetterPhone.Dial()"隐藏了继承的成员"COmpanyA.Phone.Dial"
如果是有意隐藏,请使用关键字new

该警告告诉开发人员,BetterPhone类正在定义这个Dial方法,他会隐藏Phone类定义的Dial。

解决办法就是在BetterPhone类中定义Dial时,在前面加一个new关键字。

以下是改正后的BetterPhone类

namespace CompanyB
{
    public class BetterPhone:CompanyA.Phone
    {
        public new void Dial
        {
            Console.WriteLine("BetterPhone.Dial");
            EstablishConnection();
            base.Dial();
        }
        protected virtual void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
            //在这里执行建立连接的操作
        }
    }
}

现在CompanyB能正常使用BetterPhone.Dial。

以下是CompanyB可能写的一些示例代码。

public sealed class Program()
{
    public static void Main
    {
        CompanyB.BetterPhone phone=new CompanyB.BetterPhone();
        phone.Dial();
    }
}

运行以上代码,输出结果如下所示

BetterPhone.Dial
BetterPhone.EstablishConnection
Phone.Dial

隐藏基类同名的虚方法

现在,假定几家公司计划使用CompanyA的Phone类型,再假定这几家公司都认为在Dial方法中建立连接的主意非常好。CompanyA决定对这个Phone类进行修订。

namespace CompanyA
{
    public class Phone
    {
        public void Dial
        {
            Console.WriteLine("Phone.Dial");
            EstablishConnection();
            //在这里执行拨号操作
        }
        protected virtual void EstablishConnection()
        {
            Console.WriteLine("Phone.EstablishConnection");
            //在这里执行建立连接的操作
        }
    }
}

现在,一旦CompanyB编译他的BetterPhone类型就会生成以下警告

warning CS0114:"CompanyB.BetterPhone.EstablishConnection()"
将隐藏继承的成员"CompanyA.Phone.EstablishConnection()"
若要使当前成员重写该类型,请天假关键字override否则,添加关键字new。

如果CompanyB认定EstablishConnection方法在两个类型的语义不一致,

CompanyB可以告诉编译器使用BetterPhone类中定义的Dial和EstablishConnection方法,他们与基类型Phone中的没有关系。

CompanyB可以为EstablishConnection方法添加new关键字来告诉编译器这一点。

namespace CompanyB
{
    public class BetterPhone:CompanyA.Phone
    {
        public new void Dial
        {
            Console.WriteLine("BetterPhone.Dial");
            EstablishConnection();
            base.Dial();
        }
        protected new virtual void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
            //在这里执行建立连接的操作
        }
    }
}

在这段代码中,关键字new告诉编译器生成元数据,让CLR知道BetterPhone类型的EstablishConnection方法应被视为由BetterPhone类型引入的新函数。

执行相同的应用程序代码,输出结果如下所示

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

如果更改方法名只会造成源代码发生适度更新,就应该更改方法名,避免Dial和EstablishConnection方法的两种不同含义是开发人员产生混淆。

将派生类虚方法改为重写基类的方法,实例方法继承自基类

还有一个办法是,CompanyB可以获得CompanyA的新版本Phone类型,并确定Dial和EstablishConnection在Phone中的语义正好是他们所希望的。

这种情况,CompanyB可以通过完全移除Dial方法来修改他们的BetterPhone类型。另外,由于CompanyB希望告诉编译器两类型的EstablishConnection方法是相关的,必须移除new关键字。为了准确表达意图,CompanyB的开发人员必须将BetterPhone的EstablishConnection方法由virtual改编为override。以下代码展示了新版本的BetterPhone类。

namespace CompanyB
{
    public class BetterPhone:CompanyA.Phone
    {
        //删除Dial方法,从基类继承
        protected override void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
            //在这里执行建立连接的操作
        }
    }
}

执行相同的应用程序代码,输出结果如下所示。

Phone.Dial
BetterPhone.EstablishConnection

猜你喜欢

转载自www.cnblogs.com/errornull/p/9757650.html
今日推荐