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

发布于 2024-08-13 21:00:17 字数 431 浏览 2 评论 0原文

如果我有以下代码示例:

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

If i have the following code example:

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;
    }
}

What should I do to hide the property Name (Don't shown as a member of ClassA members) without modifying ClassBase ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

那伤。 2024-08-20 21:00:17

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

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

I smell a code smell here. It is my opinion that you should only inherit a base class if you're implementing all of the functionality of that base class. What you're doing doesn't really represent object oriented principles properly. Thus, if you want to inherit from your base, you should be implementing Name, otherwise you've got your inheritance the wrong way around. Your class A should be your base class and your current base class should inherit from A if that's what you want, not the other way around.

However, not to stray too far from the direct question. If you did want to flout "the rules" and want to continue on the path you've chosen - here's how you can go about it:

The convention is to implement the property but throw a NotImplementedException when that property is called - although, I don't like that either. But that's my personal opinion and it doesn't change the fact that this convention still stands.

If you're attempting to obsolete the property (and it's declared in the base class as virtual), then you could either use the Obsolete attribute on it:

[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;
    }
}

(Edit: As Brian pointed out in the comments, the second parameter of the attribute will cause a compiler error if someone references the Name property, thus they won't be able to use it even though you've implemented it in derived class.)

Or as I mentioned use NotImplementedException:

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

However, if the property isn't declared as virtual, then you can use the new keyword to replace it:

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

You can still use the Obsolete attribute in the same manner as if the method was overridden, or you can throw the NotImplementedException, whichever you choose. I would probably use:

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

or:

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

Depending on whether or not it was declared as virtual in the base class.

瞎闹 2024-08-20 21:00:17

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

[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; }
}
  • Browsable - 成员是否显示在“属性”窗口中
  • EditorBrowsable - 成员是否显示在Intellisense 下拉菜单

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

While technically the property won't be hidden, one way to strongly discourage its use is to put attributes on it like these:

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

This is what System.Windows.Forms does for controls that have properties that don't fit. The Text property, for instance, is on Control, but it doesn't make sense on every class that inherits from Control. So in MonthCalendar, for instance, the Text property appears like this (per the online reference source):

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • Browsable - whether the member shows up in the Properties window
  • EditorBrowsable - whether the member shows up in the Intellisense dropdown

EditorBrowsable(false) won't prevent you from typing the property, and if you use the property, your project will still compile. But since the property doesn't appear in Intellisense, it won't be as obvious that you can use it.

童话 2024-08-20 21:00:17

只需隐藏它即可。

 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 的公共成员,考虑到不更改基类的约束,无法阻止这种情况。

Just hide it

 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;
    }
}

Note: Name will still be a public member of ClassBase, given the constraint of not changing the base class there is no way to stop that.

浅听莫相离 2024-08-20 21:00:17

为什么在没有必要的时候强制继承呢?
我认为正确的方法是使用 has-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;
    }
}

Why force inheritance when it's not necessary?
I think the proper way of doing it is by doing has-a instead of 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;
    }
}
清欢 2024-08-20 21:00:17

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

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

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

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

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

I don’t think a lot of the people replying here understand inheritance at all. There is a need to inherit from a base class and hide its once public var’s and functions. Example, lets say you have a basic engine and you want to make a new engine that is supercharged. Well, 99% of the engine you will use but you will tweak a bit of its functionality to make it run much better and yet still there is some functionality that should only be shown to the modifications made, not the end user. Because we all know that every class MS puts out doesn’t really ever need any modifications.

Besides using the new to simply override the functionality it is one of the things that Microsoft in their infinite wis….. oh, I mean mistakes considered a tool not worthwhile anymore.

The best way to accomplish this now is multi-level inheritance.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

Class B does all your work and class C exposes what you need exposed.

北方的韩爷 2024-08-20 21:00:17

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

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

You can't, that's the whole point of inheritance: the subclass must offer all methods and properties of the base class.

You could change the implementation to throw an exception when the property is called (if it were virtual)...

世界如花海般美丽 2024-08-20 21:00:17

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

I completely agree that properties should not be removed from base classes, but sometimes a derived class might have a different more appropriate way to enter the values. In my case, for example, I am inheriting from ItemsControl. As we all know, ItemsControl has the ItemsSource property, but I want my control to merge data from 2 sources (for example, Person and Location). If I were to have the user enter the data using ItemsSource, I would need to separate and then recombine the values, so I created 2 properties to enter the data. But back to the original question, this leaves the ItemsSource, which I do not want the user to use because I am "replacing" it with my own properties. I like the Browsable and EditorBrowsable ideas, but it still does not prevent the user from using it. The basic point here is that inheritance should keep MOST of the properties, but when there is a large complex class (especially ones where you cannot modify the original code), rewriting everything would be very inefficient.

你在看孤独的风景 2024-08-20 21:00:17

您可以使用Browsable(false)

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

You can use Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
辞旧 2024-08-20 21:00:17

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

为什么?

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

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

我使用的基本规则:

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

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

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

I think it is bad design if you have to do this, especially if you are able to design the code from the ground up.

Why?

Good design is to let the base-class share common properties that a certain concept has (virtual or real). Example: System.IO.Stream in C#.

Further down the lane bad design will increase the cost for maintenance and make implementation harder and harder. Avoid this as much as possible!

Basic rules which I use:

  • Minimize the number of properties and methods in the base-class. If you do not expect to use some properties or methods in a class that inherits the base class; do not put it in the baseclass then. If you are in the developmentstage of a project; always go back to the drawing-board now an then to check the design because things change! Redesign when needed. When your project is live the costs for changing things later in the design will go up!

    • If you are using a baseclass implemented by a 3:rd party, consider "go up" one level instead of "overriding" with "NotImplementedException" or such. If there is no other level, consider design the code from scratch.

    • Always consider to seal classes you do not want anyone to be able to inherit it. It forces coders to "go up one level" in the "inheritance- hierarchy" and thus "loose ends" like "NotImplementedException" can be avoided.

彼岸花似海 2024-08-20 21:00:17

我知道这个问题很老了,但是你可以做的是重写 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");
    }

I know that the question is old, but what you can do is override the PostFilterProperties like this:

 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");
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文