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

Ahm*_*gdy 43 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Ben*_*ter 62

我闻到了代码味道.我认为,如果要实现该基类的所有功能,则只应继承基类.你正在做的事情并不能真正代表面向对象的原则.因此,如果你想从你的基础继承,你应该实现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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

public override string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public new string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

您仍然可以像覆盖方法一样使用Obsolete属性,或者您可以抛出NotImplementedException,无论您选择哪个.我可能会用:

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

要么:

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

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

  • 过时的属性还有第二个参数,指定使用该属性应该被视为错误.此时您应该得到编译时错误,这很有帮助. (7认同)
  • 你有一个文本框。除非您想对其进行子类化,以便它只接受数字。.Text 属性(字符串)在这里没有意义。如果它是 int 或 double,它可能有一些价值,但作为字符串,它是无用的。因为输入到数字转换的正确位置是在子类的“内部”。您是否建议该控件不应继承自 TextBox?这就是您可能想要这样做的原因的一个例子。 (2认同)

Rya*_*ndy 33

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

[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]
Run Code Online (Sandbox Code Playgroud)

这就是System.Windows.Forms为具有不适合的属性的控件所做的事情.该文本属性,例如,是在控制,但它不会使每个继承自Control类的感觉.所以在MonthCalendar中,例如,它看起来像这样(每个Reflector):

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

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


CCo*_*ron 24

只是隐藏它

 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 使用这种方法,在`ClassA`之外执行类似`ClassA.Name`的操作将公开`ClassBase.Name`属性."新"成员不可能获得比最初声明的更受限制的访问权限. (4认同)
  • 而不是关于为什么不应该这样做的所有言论......这是我正在寻找的实际答案。出于序列化目的,我真的需要这个。这提供了我完美需要的解决方案!非常感谢! (2认同)

fla*_*ayn 5

为什么在不必要时强制继承?我认为执行此操作的正确方法是执行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;
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

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

\n\n

除了使用新功能来简单地覆盖功能之外,它也是 Microsoft 在其无限 wis\xe2\x80\xa6 中所做的事情之一。哦,我的意思是错误认为不再值得的工具。

\n\n

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

\n\n
public class classA \n{\n}\n\npublic class B : A \n{} \n\npublic class C : B \n{} \n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n