【问题标题】:.NET inheritance: suppress a property from the base class.NET 继承:禁止来自基类的属性
【发布时间】:2010-01-19 22:30:47
【问题描述】:

考虑 Employee、Manager 和 Assistant 类:

public class Emp
{
    public string Name { get; set; }
    public Manager Manager { get; set; }
    public Assistant Assistant { get; set; }
}

public class Manager : Emp
{ 
}

public class Assistant : Emp
{
}

目标是禁止一段代码访问这样的属性:

var foo = new Manager();
var elmo = new Emp();
elmo.Manager = foo;
elmo.Manager.Manager = new Manager(); 
//how to disallow access to Manager.Manager ?

因为Manager 继承自Emp,所以它具有.Manager.Assistant 属性。

问题

.NET 的继承实现中是否有任何修饰符可以删除 .Manager.Assistant 属性?

更新

谢谢大家的精彩回答。我希望 Emp/Mgr 的简化和设计能在这个问题中体现出来。很明显,在这个例子中,继承应该被带到另一个共同点(比如Person,类将共享名称、生日等)非常感谢您的输入!

【问题讨论】:

  • 对我来说闻起来像是设计问题。虽然经理可能会向另一位经理汇报,但助理可能没有助理。也许基础应该是 Person...

标签: c# .net inheritance


【解决方案1】:

这样做会违反Liskov substitution principle,通常表示设计存在问题。一般来说,任何子类都应该能够在基类的任何上下文中使用。如果Managers 没有.Managers,那么它们就不是Emps,也不应该从它们继承。

【讨论】:

    【解决方案2】:

    不-因为它会破坏Liskov's Subsitution Principle。基本上,您可以添加东西,但不能将它们带走。

    您可能会覆盖该属性以在执行时引发异常,但您不能在编译时这样做。

    一般来说,如果你想禁止这种事情,你应该考虑组合而不是继承,因为你没有真正的继承关系。

    【讨论】:

      【解决方案3】:

      不,没有。

      您可以创建基类属性virtual,然后覆盖它以在setter 中抛出异常,但是没有办法给出编译时错误。毕竟,你在编译时没有做任何事情来阻止

      (elmo.Manager as Employee).Manager = new Manager();
      

      但是,你可以写

      public class ManagerEmployee : Emp {     
          public new ManagerEmployee Manager { 
              get { return base.Manager; }
          }
      }
      

      请注意,这不会阻止投射。

      【讨论】:

        【解决方案4】:

        像大多数事情一样,这取决于。给定以下类:

        public class foo
        {
            public string Test { get { return "foo"; } } 
        }
        
        public class bar : foo
        {
            public new string Test { get { return "bar"; } }
        }
        

        还有如下代码:

                bar a = new bar();
                // returns bar
                literalTest1.Text = a.Test;
        
                foo b = new foo();
                // returns "foo"
                literalTest2.Text = b.Test;
        
                foo c = new bar();
                // returns "foo"
                literalTest3.Text = c.Test;
        

        您可以看到,根据上面的 cmets,您可以覆盖未声明为虚拟的属性。但是,仅当对象变量被声明为覆盖该属性的类型时才会使用被覆盖的属性 - 而不是它的任何祖先。这有效地破坏了多态性。

        改为修复您的祖先类。

        【讨论】:

          【解决方案5】:

          正如其他人所说。不。我要补充一点,如果不是每个员工都有经理和助理,那么您的继承层次结构是错误的。似乎员工和经理唯一共享的就是名字。您可以通过继承添加,但不能通过继承删除。

          【讨论】:

            【解决方案6】:

            不,您不能这样做,而且您也不想这样做 - 经理是员工并且有经理和助理,或者没有,因此应该有不同的基类,即这种情况表明设计缺陷。一种可能性是为这些属性返回 null,但如果这对域有意义。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-05-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-10-02
              • 1970-01-01
              相关资源
              最近更新 更多