从派生类隐藏属性

JDo*_*Doe 6 c# inheritance

Jon Skeet在他的视频中提到了这个问题(虽然没有提供答案).

假设我们有一个名为Person的类,而Person类具有Name属性

然后我们有另一个班,间谍.当然,间谍是一个人,所以我们将从Person类派生.

public class Person
{
    public string Name { get; set; }
}

public class Spy : Person
{

}
Run Code Online (Sandbox Code Playgroud)

我们不希望人们知道Spy的名字,所以我们希望这会给出一个编译错误:

static void ReportSpy(Spy spy) {
  string name = spy.Name;
}
Run Code Online (Sandbox Code Playgroud)

或者:

static void ReportSpy(Spy spy)
{
   Person spyAsPerson = spy;
   string name = spyAsPerson.Name;
}
Run Code Online (Sandbox Code Playgroud)

我们怎么能防止这种事情发生呢?

Arg*_*a C 6

使Name财产virtual在基Person类.在派生Spy类中,覆盖属性和throw Exceptiongetter.

public class Person
{
    public virtual string Name { get; set; }
}

public class Spy : Person
{
    public override string Name
    {
        get
        {
            throw new Exception("You never ask for a spy's name!");
        }
        set
        {
            base.Name = value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我建议不要抛出异常

get
{
    return "**********";
}
Run Code Online (Sandbox Code Playgroud)

因为,它打破了LSP(在另一个答案中提到).这意味着什么(只是一个例子),我总是可以这样做

Person x = new Spy();
Run Code Online (Sandbox Code Playgroud)

并将其传递给其他方法,可能就像

void RegisterForNextBallGame(Person p)
{
    playerList.Add(p.Name);
}
Run Code Online (Sandbox Code Playgroud)

这种方法不知道体育场周围的一些间谍漫游,在做一个简单的诚实任务时崩溃!

编辑

只是要清楚,这name=**********还没有一个合适的解决方案.它只会从异常中拯救!之后,人们可能会发现许多人在名称为**********的代码中走下来,这将导致后来的惊喜和其他问题.

更好的解决方案是更好的设计.检查内森的答案以获得一些暗示.


Nat*_*per 6

如果作为一个人的一部分透露了你的名字:间谍不是人

让间谍继承人破坏了Liskov替换原则:一个对象可以用它的子类型替换.

如果Spys没有透露他们的名字,他们就不应该是您设计环境中的人物.也许您可以设计不同的方式:

public interface IPerson
{
    void EatLunch();
}

public interface INameDisclosingPerson : IPerson
{
    string Name {get; set; }
}

public interface ISpy : IPerson
{
    void DrinkCocktail();
    Package MakeDrop();
}
Run Code Online (Sandbox Code Playgroud)

现实世界中这种糟糕设计的一个例子是NetworkStream.它Position通过抛出NotSupportedException来实现该属性.因此,您为a编写的代码Stream可能会在运行时中断NetworkStream.我也不是这个的粉丝.一个设计指南:错误的东西应该在编译时破坏,从它们无法实现的接口继承的对象是可怕的.