如何在不修改继承类(基类)的情况下隐藏类中继承的属性?
-
18-09-2019 - |
题
如果我有以下代码示例:
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
(不显示为A类成员)无需修改 ClassBase
?
解决方案
我在这里闻到了代码的味道。我认为,只有在实现基类的所有功能时才应该继承该基类。您所做的并没有真正正确地代表面向对象的原则。因此,如果你想从你的基础继承,你应该实现 Name,否则你的继承方式是错误的。你的类 A 应该是你的基类,如果你想要的话,你当前的基类应该继承自 A,而不是相反。
然而, 不要偏离直接问题太远。如果你 做过 想要藐视“规则”并想要继续走你选择的道路 - 以下是你可以采取的方法:
约定是实现该属性,但在调用该属性时抛出 NotImplementedException - 尽管我也不喜欢这样。但这是我个人的观点,并不能改变这个惯例仍然有效的事实。
如果您尝试废弃该属性(并且在基类中将其声明为 virtual),那么您可以对其使用 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();
}
}
然而,如果该房产 不是 声明为virtual,那么可以使用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; }
取决于它是否在基类中声明为虚拟的。
其他提示
虽然从技术上讲,该属性不会被隐藏,但强烈阻止其使用的一种方法是在其上添加如下属性:
[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]
这就是 System.Windows.Forms 对具有不合适属性的控件所做的事情。这 文本 例如,属性位于 Control 上,但它对于从 Control 继承的每个类都没有意义。所以在 月历, 例如,Text 属性如下所示(根据在线参考源):
[Browsable(false),
EditorBrowsable(EditorBrowsableState.Never),
Bindable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
get { return base.Text; }
set { base.Text = value; }
}
- 可浏览 - 成员是否显示在“属性”窗口中
- 编辑器可浏览 - 成员是否出现在智能感知下拉列表中
EditorBrowsable(false) 不会阻止您输入该属性,并且如果您使用该属性,您的项目仍将编译。但由于该属性没有出现在 Intellisense 中,因此您可以使用它不会那么明显。
只是隐藏它
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 的公共成员,考虑到不更改基类的约束,没有办法阻止这种情况。
为什么在没有必要的时候强制继承呢?我认为正确的做法是这样做 有一个 代替 是一个.
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;
}
}
我完全同意不应从基类中删除属性,但有时派生类可能有不同的更合适的方法来输入值。例如,就我而言,我继承自 ItemsControl。众所周知,ItemsControl 具有 ItemsSource 属性,但我希望我的控件合并来自 2 个源(例如,人员和位置)的数据。如果我要用户使用 ItemsSource 输入数据,我需要分离然后重新组合这些值,因此我创建了 2 个属性来输入数据。但回到最初的问题,这留下了 ItemsSource,我不希望用户使用它,因为我用我自己的属性“替换”它。我喜欢 Browsable 和 EditorBrowsable 的想法,但这仍然不妨碍用户使用它。这里的基本点是继承应该保留大部分属性,但是当存在一个大型复杂类(尤其是无法修改原始代码的类)时,重写所有内容将非常低效。
我认为很多在这里回复的人根本不理解继承。需要从基类继承并隐藏其曾经的公共变量和函数。例如,假设您有一个基本发动机,并且您想要制造一个增压的新发动机。好吧,您将使用 99% 的引擎,但您将对其功能进行一些调整以使其运行得更好,但仍然有一些功能应该只向所做的修改显示,而不是向最终用户显示。因为我们都知道 MS 推出的每个类别实际上都不需要任何修改。
除了使用新功能来简单地覆盖功能之外,这是微软无限智慧的事情之一......哦,我的意思是错误被认为是不再值得的工具。
现在实现这一点的最佳方法是多级继承。
public class classA
{
}
public class B : A
{}
public class C : B
{}
B 类完成您的所有工作,C 类公开您需要公开的内容。
你不能,这就是继承的全部意义:子类必须提供基类的所有方法和属性。
您可以更改实现以在调用属性时引发异常(如果它是虚拟的)...
我认为如果您必须这样做,那么这是糟糕的设计,特别是如果您能够从头开始设计代码。
为什么?
好的设计是让基类共享某个概念所具有的共同属性(虚拟的或真实的)。例子:C# 中的 System.IO.Stream。
再往下走,糟糕的设计将增加维护成本,并使实施变得越来越困难。尽量避免这种情况!
我使用的基本规则:
尽量减少基类中属性和方法的数量。如果你不希望使用继承基类的类中的某些属性或方法;那么不要把它放在基类中。如果您正处于项目的开发阶段;总是时不时地回到绘图板检查设计,因为事情会发生变化!需要时重新设计。当您的项目上线时,设计后期更改内容的成本将会上升!
如果您使用的是由第三方实现的基类,请考虑“上升”一级,而不是使用“NotImplementedException”等“覆盖”。如果没有其他级别,请考虑从头开始设计代码。
始终考虑密封您不希望任何人能够继承的类。它迫使编码人员在“继承层次结构”中“上升一级”,从而可以避免像“NotImplementedException”这样的“松散的结局”。
我知道这个问题很老了,但是你可以做的是重写 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");
}
您可以使用 Browsable(false)
[Browsable( false )]
public override string Name
{
get { return base.Name; }
set { base.Name= value; }
}