2011-05-18 90 views
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; } 
} 

有什么办法使密封防止财产在派生类中被重写的BaseBook基类Title财产(如BookSuperBook类)?

+0

你为什么要这样的事情?有什么特别的原因让用户不应该被允许覆盖你的财产? – 2011-05-18 13:11:33

回答

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 

如果您的虚拟财产,那么结果是最派生实现总是会被调用,因为编译器使用一个虚拟表,找到调用哪个方法。

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

3

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

1

无论如何,您将无法覆盖Title属性,除非它标记为virtual。有些人使用new操作员隐藏了你无法阻止的内容。

+0

是的,你是对的:''''''你无法阻止它被使用新操作符的人隐藏。 – 2011-05-19 09:52:50

1

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

-3

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

+0

这不起作用,因为标题不是虚拟的,因此不能密封。 – Gal 2011-05-18 14:11:39