抽象类的密封属性
请考虑以下设计:
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
属性被密封以防止在派生类(例如Book
和SuperBook
类)中重写属性?
如果您编译程序,您将收到以下警告:
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
。
如果它不是虚拟的,那么它不能被覆盖,它只能被隐藏(使用new
关键字)。 与Java不同,C#方法(以及扩展属性)不是隐式虚拟的,而是显式的。
除非标记为virtual
,否则您将无法覆盖Title
属性。 你不能阻止它被使用new
运算符的人隐藏。
您已经无法覆盖BaseBook.Title。 SuperBook.Title实际上隐藏了BaseBook.Title而不是覆盖它。 如果打算隐藏它,它应该真的有新的关键字; 事实上,你会得到一个编译器警告这种效果。
在Title属性上使用“sealed”关键字。