web-dev-qa-db-ja.com

継承されたクラス(基本クラス)を変更せずに、クラスの継承されたプロパティを非表示にする方法

次のコード例がある場合:

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メンバーのメンバーとして表示されない)を非表示にするにはどうすればよいですか?

42
Ahmed Magdy

ここでコードのにおいがします。その基本クラスのすべての機能を実装する場合にのみ、基本クラスを継承する必要があるというのが私の意見です。あなたがしていることは、実際にはオブジェクト指向の原則を適切に表していません。したがって、ベースから継承する場合は、Nameを実装する必要があります。そうしないと、間違った方法で継承を取得することになります。クラスAは基本クラスであり、現在の基本クラスは、必要に応じてAから継承する必要があり、逆ではありません。

ただし直接の質問から遠すぎないようにします。 didが「ルール」を無視し、選択したパスを続行したい場合は、次のようにします。

慣例では、プロパティを実装しますが、そのプロパティが呼び出されたときに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;
    }
}

編集:ブライアンがコメントで指摘したように、誰かがNameプロパティを参照する場合、属性の2番目のパラメーターはコンパイラエラーを引き起こします。したがって、派生クラスで実装しました。)

または、前述のようにNotImplementedExceptionを使用します。

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

ただし、プロパティが仮想として宣言されていない場合、新しいキーワードを使用して置き換えることができます。

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

基本クラスで仮想として宣言されたかどうかによって異なります。

60
BenAlabaster

技術的にはプロパティは非表示になりませんが、その使用を強く思いとどまらせる1つの方法は、次のような属性を設定することです。

[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に表示されないため、使用できることはそれほど明白ではありません。

30
Ryan Lundy

隠すだけ

 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のパブリックメンバーのままです。これを止める方法はありません。

24
CCondron

なぜ必要ないのに継承を強制するのですか?適切な方法は、is-aの代わりにhas-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
flayn

プロパティを基本クラスから削除すべきではないことに完全に同意しますが、派生クラスには値を入力するための別のより適切な方法がある場合があります。私の場合、たとえば、ItemsControlから継承しています。ご存知のように、ItemsControlにはItemsSourceプロパティがありますが、2つのソース(PersonとLocationなど)からのデータをコントロールにマージする必要があります。 ItemsSourceを使用してユーザーにデータを入力させる場合、値を分離してから再結合する必要があるため、2つのプロパティを作成してデータを入力します。しかし、元の質問に戻って、これはItemsSourceを残します。これは、ユーザーが自分のプロパティで「置換」しているため、ユーザーに使用させたくありません。私はBrowsableとEditorBrowsableのアイデアが好きですが、それでもユーザーがそれを使用することを妨げません。ここでの基本的なポイントは、継承がプロパティのMOSTを保持する必要があることですが、大きな複雑なクラス(特に元のコードを変更できないクラス)がある場合、すべてを書き換えることは非常に非効率的です。

2
Nathan Sokalski

ここで返信する人の多くは、継承をまったく理解していないと思います。基本クラスから継承し、かつてパブリック変数と関数を非表示にする必要があります。たとえば、基本的なエンジンがあり、スーパーチャージされた新しいエンジンを作りたいとしましょう。使用するエンジンの99%ですが、機能を少し調整して実行を改善しますが、エンドユーザーではなく、行われた変更に対してのみ表示される機能があります。なぜなら、MSが出すすべてのクラスが実際に修正を必要とすることはないからです。

新しい機能を使用して単純に機能をオーバーライドすることに加えて、それはMicrosoftが無限の知恵を持っていることの1つです。

これを実現する最善の方法は、マルチレベルの継承です。

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

クラスBはすべての作業を行い、クラスCは必要なものを公開します。

2
engnrman

それは継承のすべてのポイントです。サブクラスは基本クラスのすべてのメソッドとプロパティを提供する必要があります。

プロパティが呼び出されたときに例外をスローするように実装を変更できます(仮想の場合)...

1
Fried Hoeben

私は質問が古いことを知っていますが、あなたができることは次のように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");
    }
0
Nane

Browsable(false)を使用できます

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

これを行う必要がある場合、特にコードを一から設計できる場合は、設計が悪いと思います。

どうして?

良い設計は、特定の概念が持つ共通のプロパティ(基本または実)を基本クラスで共有できるようにすることです。例:C#のSystem.IO.Stream。

レーンの設計が悪いと、メンテナンスのコストが増加し、実装がますます難しくなります。これをできるだけ避けてください!

私が使用する基本的なルール:

  • 基本クラスのプロパティとメソッドの数を最小限にします。基本クラスを継承するクラスで一部のプロパティまたはメソッドを使用する予定がない場合。その場合、ベースクラスに入れないでください。プロジェクトの開発段階にいる場合;物事が変わるので、デザインを確認するために、今は常に図面に戻ってください!必要に応じて再設計します。プロジェクトがライブになると、デザインの後半で変更するためのコストが上がります!

    • サードパーティによって実装されたベースクラスを使用している場合は、「NotImplementedException」などで「オーバーライド」するのではなく、1レベル上に「上に行く」ことを検討してください。他にレベルがない場合は、コードをゼロから設計することを検討してください。

    • 誰にも継承させたくないクラスを封印することを常に考慮してください。これにより、コーダーは「継承階層」で「1レベル上がる」ように強制されるため、「NotImplementedException」のような「ルーズエンド」を回避できます。

0
user3567581