如何在不修改继承类(基类)的情况下隐藏类中的继承属性?

时间:2009-12-09 17:14:23

标签: c# inheritance properties base-class

如果我有以下代码示例:

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA : ClassBase
{
    public int JustNumber { get; set; }

    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}

如何在不修改Name的情况下隐藏属性ClassBase(不显示为ClassA成员)?

10 个答案:

答案 0 :(得分:60)

我闻到了代码味道。我认为,如果要实现该基类的所有功能,则只应继承基类。你正在做的事情并不能真正代表面向对象的原则。因此,如果你想从你的基础继承,你应该实现Name,否则你的继承是错误的。你的A类应该是你的基类,你的当前基类应该继承自A,如果这是你想要的,而不是相反。

然而,不要偏离直接问题太远。如果你 希望藐视“规则”并希望继续你选择的道路 - 这就是你如何去做的事情:

约定是实现属性,但在调用该属性时抛出NotImplementedException - 尽管如此,我也不喜欢它。但这是我个人的意见,并没有改变这个惯例仍然存在的事实。

如果您试图废弃该属性(并且它在基类中声明为虚拟),那么您可以使用它上面的Obsolete属性:

[Obsolete("This property has been deprecated and should no longer be used.", true)]
public override string Name 
{ 
    get 
    { 
        return base.Name; 
    }
    set
    {
        base.Name = value;
    }
}

编辑:正如Brian在评论中指出的那样,如果某人引用了Name属性,该属性的第二个参数将导致编译器错误,因此他们甚至无法使用它虽然你已经在派生类中实现了它。)

或者正如我提到的那样使用NotImplementedException:

public override string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

但是,如果属性不是声明为虚拟,那么您可以使用new关键字替换它:

public new string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

您仍然可以使用与重写方法相同的方式使用Obsolete属性,或者您可以抛出NotImplementedException,无论您选择哪个。我可能会用:

[Obsolete("Don't use this", true)]
public override string Name { get; set; }

或:

[Obsolete("Don't use this", true)]
public new string Name { get; set; }

取决于它是否在基类中声明为虚拟。

答案 1 :(得分:29)

虽然技术上不会隐藏属性,但强烈建议不要使用它的一种方法是将属性放在上面:

[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]

这就是System.Windows.Forms为具有不适合的属性的控件所做的事情。例如, Text 属性在Control上,但是对于从Control继承的每个类都没有意义。因此,在MonthCalendar中,它看起来像这样(每个Reflector):

[Browsable(false), Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
    EditorBrowsable(EditorBrowsableState.Never)]
public override string Text
{
    get { return base.Text; }
    set { base.Text = value; }
}

可浏览表示该成员是否显示在“属性”窗口中。 EditorBrowsable 表示它是否显示在Intellisense下拉列表中。如果将EditorBrowsable设置为false,您仍然可以键入该属性,并且它仍然可以构建,但是您不能使用它。

答案 2 :(得分:23)

隐藏它

 public class ClassBase
{
    public int ID { get; set; }
    public string Name { get; set; }
}
public class ClassA : ClassBase
{
    public int JustNumber { get; set; }
    private new string Name { get { return base.Name; } set { base.Name = value; } }
    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = 0;
    }
}

注意:Name仍然是ClassBase的公共成员,考虑到不更改基类的约束,没有办法阻止它。

答案 3 :(得分:4)

为什么在没有必要时强制继承呢? 我认为正确的做法是通过 has -a 而不是是-a

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA
{
    private ClassBase _base;

    public int ID { get { return this._base.ID; } }

    public string JustNumber { get; set; }

    public ClassA()
    {
        this._base = new ClassBase();
        this._base.ID = 0;
        this._base.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}

答案 4 :(得分:2)

我认为很多在这里回复的人都不了解遗产。需要从基类继承并隐藏其曾经的公共变量和函数。例如,假设您有一个基本的引擎,并且您想要制造一个增压的新引擎。好吧,你将使用99%的引擎,但你会调整它的一些功能,使其运行得更好,但仍然有一些功能只应显示给所做的修改,而不是最终用户。因为我们都知道MS推出的每个类都不需要任何修改。

除了使用新功能简单地覆盖功能之外,它还是微软无限智慧的事情之一......哦,我的意思是错误被认为是一个不值得的工具。

现在实现这一目标的最佳方法是多级继承。

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

B类完成所有工作,C类暴露您需要暴露的内容。

答案 5 :(得分:2)

我完全同意不应该从基类中删除属性,但有时派生类可能有更合适的方法来输入值。例如,在我的情况下,我继承自ItemsControl。众所周知,ItemsControl具有ItemsSource属性,但我希望我的控件合并来自2个源(例如,Person和Location)的数据。如果我让用户使用ItemsSource输入数据,我需要分离然后重新组合值,所以我创建了2个属性来输入数据。但回到最初的问题,这就留下了ItemsSource,我不希望用户使用它,因为我用自己的属性“替换”它。我喜欢Browsable和EditorBrowsable的想法,但它仍然不能阻止用户使用它。这里的基本点是继承应该保留MOST的属性,但是当存在大型复杂类(特别是那些无法修改原始代码的类)时,重写所有内容将是非常低效的。

答案 6 :(得分:1)

你不能,这就是继承的全部要点:子类必须提供基类的所有方法和属性。

您可以更改实现以在调用属性时抛出异常(如果它是虚拟的)...

答案 7 :(得分:0)

我认为如果你必须这样做是不好的设计,特别是如果你能够从头开始设计代码。

为什么?

好的设计是让基类共享某个概念具有的共同属性(虚拟或真实)。示例:C#中的System.IO.Stream。

更糟糕的是,糟糕的设计将增加维护成本并使实施变得更加困难。尽可能避免这种情况!

我使用的基本规则:

  • 最小化基类中的属性和方法的数量。如果您不希望在继承基类的类中使用某些属性或方法;不要把它放在基类中。如果您正处于项目的开发阶段;现在总是回到绘图板然后检查设计因为事情发生了变化!需要时重新设计。当您的项目生效时,设计后期更改内容的成本将会上升!

    • 如果您使用的是由第三方实施的基类,请考虑" go up"一级而不是"覆盖" with" NotImplementedException"或者这样的。如果没有其他级别,请考虑从头开始设计代码。

    • 始终考虑密封您不希望任何人继承它的课程。它迫使程序员上升到一个水平"在"继承 - 层级"因此"松散的结束"喜欢" NotImplementedException"可以避免。

答案 8 :(得分:0)

我知道这个问题很旧,但你可以做的是覆盖PostFilterProperties,如下所示:

 protected override void PostFilterProperties(System.Collections.IDictionary properties)
    {
        properties.Remove("AccessibleDescription");
        properties.Remove("AccessibleName");
        properties.Remove("AccessibleRole");
        properties.Remove("BackgroundImage");
        properties.Remove("BackgroundImageLayout");
        properties.Remove("BorderStyle");
        properties.Remove("Cursor");
        properties.Remove("RightToLeft");
        properties.Remove("UseWaitCursor");
        properties.Remove("AllowDrop");
        properties.Remove("AutoValidate");
        properties.Remove("ContextMenuStrip");
        properties.Remove("Enabled");
        properties.Remove("ImeMode");
        //properties.Remove("TabIndex"); // Don't remove this one or the designer will break
        properties.Remove("TabStop");
        //properties.Remove("Visible");
        properties.Remove("ApplicationSettings");
        properties.Remove("DataBindings");
        properties.Remove("Tag");
        properties.Remove("GenerateMember");
        properties.Remove("Locked");
        //properties.Remove("Modifiers");
        properties.Remove("CausesValidation");
        properties.Remove("Anchor");
        properties.Remove("AutoSize");
        properties.Remove("AutoSizeMode");
        //properties.Remove("Location");
        properties.Remove("Dock");
        properties.Remove("Margin");
        properties.Remove("MaximumSize");
        properties.Remove("MinimumSize");
        properties.Remove("Padding");
        //properties.Remove("Size");
        properties.Remove("DockPadding");
        properties.Remove("AutoScrollMargin");
        properties.Remove("AutoScrollMinSize");
        properties.Remove("AutoScroll");
        properties.Remove("ForeColor");
        //properties.Remove("BackColor");
        properties.Remove("Text");
        //properties.Remove("Font");
    }

答案 9 :(得分:0)

您可以使用Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}