繁体   English   中英

抽象类的密封属性

[英]Sealed property of abstract class

请考虑以下设计:

public interface IBook
{
    string Author { get; set; }

    string Title { get; set; }
}

abstract class BaseBook : IBook
{
    private string _title;

    public virtual string Author
    {
        get
        {
            Console.WriteLine("Base book GET!");
            return _title;
        }
        set
        {
            Console.WriteLine("Base book SET!");
            _title = value;
        }
    }

    public string Title { get; set; }
}

class Book : BaseBook
{
}

class SuperBook : Book
{
    public override string Author
    {
        get
        {
            Console.WriteLine("SuperBook GET!");
            return base.Author;
        }
        set
        {
            Console.WriteLine("SuperBook SET!");
            base.Author = value;
        }
    }

    public string Title { get; set; }
}

是否有任何方法使BaseBook基类的Title属性被密封以防止在派生类(例如BookSuperBook类)中重写属性?

如果它不是虚拟的,那么它不能被覆盖,它只能被隐藏(使用new关键字)。 与Java不同,C#方法(以及扩展属性)不是隐式虚拟的,而是显式的。

如果您编译程序,您将收到以下警告:

prog.cs(63,19):警告CS0108: SuperBook.Title' hides inherited member BaseBook.Title'。 如果要隐藏,请使用new关键字

这意味着你的SuperBook.Title隐藏了来自BaseBook的Title。 隐藏与覆盖不同,因为该成员不是虚拟的。 隐藏会发生什么:如果编译器将您的对象视为SuperBook类的实例,它将调用SuperBook.Title方法。 但是,如果编译器将您的实例视为BaseBook类,则调用BaseBook.Title

例如:

SuperBook b1 = new SuperBook();
Console.Writeline(b1.Title); // will result in a call to SuperBook.Title
BaseBook b2 = b1;
Console.Writeline(b1.Title); // will result in a call to BaseBook.Title

如果将属性设置为virtual,则结果是始终会调用派生最多的实现,因为编译器使用虚拟表来查找要调用的方法。

最后,如果您希望该属性是虚拟的,以便每个调用都被解析为SuperBook.Title ,但不希望用户在更多派生类上覆盖它,您只需要标记属性sealed override

除非标记为virtual ,否则您将无法覆盖Title属性。 你无法阻止它被使用new运算符的人隐藏。

您已经无法覆盖BaseBook.Title。 SuperBook.Title实际上隐藏了BaseBook.Title而不是覆盖它。 如果打算隐藏它,它应该真的有新的关键字; 事实上,你会得到一个编译器警告这种效果。

在Title属性上使用“sealed”关键字。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM