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

StackOverflow https://stackoverflow.com/questions/1875401

質問

次のコード例があるとします。

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 ?

役に立ちましたか?

解決

ここでコードの匂いがします。基本クラスのすべての機能を実装している場合にのみ、基本クラスを継承すべきであるというのが私の意見です。あなたがやっていることは、実際にはオブジェクト指向の原則を適切に表していません。したがって、ベースから継承したい場合は、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 プロパティを参照すると、属性の 2 番目のパラメーターはコンパイラ エラーを引き起こすため、たとえ派生クラスで実装したとしても、そのユーザーはそれを使用できません。)

または、前述したように 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; }

基本クラスで仮想として宣言されているかどうかに応じて異なります。

他のヒント

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

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

これは、適合しないプロパティを持つコントロールに対して System.Windows.Forms が行うことです。の 文章 たとえば、property は 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; }
}
  • 閲覧可能 - メンバーが「プロパティ」ウィンドウに表示されるかどうか
  • エディター閲覧可能 - メンバーが Intellisense ドロップダウンに表示されるかどうか

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

注:名前がまだそれを停止する方法がない基本クラスを変更しないという制約が与えられると、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を、残します。私は、ブラウズ可能とEditorBrowsableアイデアが好き、それはまだそれを使用してからユーザーを防ぐことはできません。ここでの基本的なポイントは、その継承プロパティのほとんどを維持する必要がありますが、大規模で複雑なクラス(あなたが元のコードを変更することはできません特にもの)があるとき、すべてを書き換えることは非常に非効率的になります。

私はここで返信多くの人が全く継承を理解しないと思います。基本クラスから継承し、そのかつてプロパティpublic varのと機能を非表示にする必要があります。例では、あなたが基本的なエンジンを持っていて、過給された新しいエンジンを作りたいと言うことができます。さて、エンジンの99%は、あなたが使用しますが、あなたはそれがより良い実行するためにその機能のビットを微調整し、それでもだけでなく、エンドユーザー、行われた変更に示すべきであるいくつかの機能があります。我々はすべてのMSが出すすべてのクラスが本当に今までに変更を必要としないことを知っているので。

は、単に機能を無効にするために、新しいを使用した以外にも、それは、Microsoftが彼らの無限のウィスコンシン州で... ..ああ、私はもうツールは価値がないと考えミスを意味するものの一つです。

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

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

クラスBは、すべての作業とクラスCは、あなたが暴露必要なものを公開しません。

あなたは、それは継承の全体のポイントだことはできません:。サブクラスは、基本クラスのすべてのメソッドとプロパティを提供しなければならない。

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

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

なぜ?

優れた設計とは、特定の概念 (仮想または現実) が持つ共通のプロパティを基本クラスに共有させることです。例:C# の System.IO.Stream。

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

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

  • 基本クラス内のプロパティとメソッドの数を最小限に抑えます。基本クラスを継承するクラスで一部のプロパティまたはメソッドを使用する予定がない場合。その場合は、それを基本クラスに入れないでください。プロジェクトの開発段階にある場合。状況が変化するため、常に今すぐ製図板に戻ってデザインをチェックしてください。必要に応じて再設計します。プロジェクトが稼働中になると、設計の後半で変更するためのコストが高くなります。

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

    • 誰にも継承させたくないクラスをシールすることを常に考慮してください。これにより、コーダは「継承階層」で「1 つ上のレベルに上がる」ことを強制されるため、「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; }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top