62

如果我有以下代码示例:

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不修改的情况下隐藏属性(不显示为 ClassA 成员的成员)ClassBase

4

10 回答 10

86

我在这里闻到了代码的味道。我认为,如果您要实现该基类的所有功能,则应该只继承该基类。您所做的并不能真正正确地代表面向对象的原则。因此,如果你想从你的基础继承,你应该实现 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; }

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

于 2009-12-09T17:18:04.170 回答
42

虽然从技术上讲,该属性不会被隐藏,但强烈反对使用它的一种方法是在其上添加如下属性:

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

这就是 System.Windows.Forms 对具有不适合的属性的控件所做的。例如,Text属性位于 Control 上,但它对从 Control 继承的每个类都没有意义。例如,在MonthCalendar中, Text 属性如下所示(根据在线参考源):

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • 可浏览- 成员是否显示在“属性”窗口中
  • EditorBrowsable - 成员是否出现在 Intellisense 下拉列表中

EditorBrowsable(false) 不会阻止您键入该属性,并且如果您使用该属性,您的项目仍将编译。但是由于该属性没有出现在 Intellisense 中,因此您可以使用它并不那么明显。

于 2009-12-09T18:01:29.200 回答
31

只是隐藏它

 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 的公共成员,鉴于不更改基类的约束,没有办法阻止它。

于 2011-02-03T23:21:32.180 回答
6

为什么在不需要的时候强制继承?我认为正确的做法是做has-a而不是 a is-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;
    }
}
于 2012-06-27T13:36:47.750 回答
3

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

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

现在实现这一点的最好方法是多级继承。

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

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

于 2012-10-04T20:47:29.583 回答
2

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

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

于 2009-12-09T17:17:14.257 回答
2

我完全同意不应从基类中删除属性,但有时派生类可能有不同的更合适的方式来输入值。例如,就我而言,我是从 ItemsControl 继承的。众所周知,ItemsControl 具有 ItemsSource 属性,但我希望我的控件合并来自 2 个源(例如,Person 和 Location)的数据。如果我要让用户使用 ItemsSource 输入数据,我需要分离然后重新组合这些值,因此我创建了 2 个属性来输入数据。但回到最初的问题,这留下了 ItemsSource,我不希望用户使用它,因为我正在用我自己的属性“替换”它。我喜欢 Browsable 和 EditorBrowsable 的想法,但它仍然不妨碍用户使用它。

于 2016-11-18T19:43:06.070 回答
1

您可以使用Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
于 2018-10-23T06:13:42.070 回答
0

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

为什么?

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

再往下走,糟糕的设计将增加维护成本,并使实施变得越来越困难。尽量避免这种情况!

我使用的基本规则:

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

    • 如果您使用的是由 3:rd 方实现的基类,请考虑“上一层”而不是使用“NotImplementedException”等“覆盖”。如果没有其他级别,请考虑从头开始设计代码。

    • 始终考虑密封您不希望任何人能够继承它的类。它迫使编码人员在“继承-层次结构”中“上一层”,因此可以避免像“NotImplementedException”这样的“松散的结局”。

于 2014-04-24T07:20:48.523 回答
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");
    }
于 2015-06-14T16:51:44.697 回答