请考虑以下设计:
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
基类密封的BaseBook
属性阻止在派生类中重写属性(例如{{1}和Book
类)?
答案 0 :(得分:3)
如果它不是虚拟的,那么它不能被覆盖,它只能被隐藏(使用new
关键字)。
与Java不同,C#方法(以及扩展属性)不是隐式虚拟的,而是显式的。
答案 1 :(得分:2)
如果您编译程序,您将收到以下警告:
prog.cs(63,19):警告CS0108:
SuperBook.Title' hides inherited member
BaseBook.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
如果将属性设置为virtual,那么结果是将始终调用派生最多的实现,因为编译器使用虚拟表来查找要调用的方法。
最后,如果您希望该属性是虚拟的,以便每个调用都解析为SuperBook.Title
,但不希望用户在更多派生类上覆盖它,那么您只需标记该属性{ {1}}。
答案 2 :(得分:1)
除非标记为Title
,否则您将无法覆盖virtual
属性。使用new
运算符的人隐藏了无法阻止它的内容。
答案 3 :(得分:1)
您已经无法覆盖BaseBook.Title。 SuperBook.Title实际上隐藏了BaseBook.Title而不是覆盖它。如果打算隐藏它,它应该真的有新的关键字;事实上,你会得到一个编译器警告。
答案 4 :(得分:-3)
在Title属性上使用“sealed”关键字。