3

请考虑以下设计:

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; }
}

有什么方法可以密封基类的Title属性,以防止该属性在派生类(例如和类)中被覆盖?BaseBookBookSuperBook

4

5 回答 5

3

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

于 2011-05-18T13:10:09.790 回答
2

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

prog.cs(63,19):警告 CS0108: SuperBook.Title' hides inherited memberBaseBook.Title'。如果打算隐藏,请使用新关键字

这意味着您SuperBook.Title正在从 BaseBook 隐藏标题。隐藏不同于覆盖,因为成员不是虚拟的。隐藏会发生什么:如果编译器将您的对象视为 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

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

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

于 2011-05-18T14:10:03.943 回答
1

Title除非它被标记,否则您将无法覆盖该属性virtual。您无法阻止它被使用new操作员的人隐藏。

于 2011-05-18T13:11:34.277 回答
1

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

于 2011-05-18T13:12:05.127 回答
-3

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

于 2011-05-18T13:12:41.553 回答