webdevqa.jp.net

C#で基本クラスのメソッドを非表示(削除)する方法は?

問題の本質は、次のようなクラス階層が与えられた場合です。

_class A
{
    protected void MethodToExpose()
    {}

    protected void MethodToHide(object param)
    {}
}

class B : A
{
    new private void MethodToHide(object param)
    {}

    protected void NewMethodInB()
    {}
}

class C : B
{
    public void DoSomething()
    {
        base.MethodToHide("the parameter"); // This still calls A.MethodToHide()
        base.MethodToExpose(); // This calls A.MethodToExpose(), but that's ok
        base.NewMethodInB();
    }
}
_

クラス「B」から継承するクラスがメソッドA.MethodToHide()を認識しないようにするにはどうすればよいですか? C++では、これは_class B : private A_などの宣言を使用することで十分簡単でしたが、この構文はC#では無効です。

興味のある人(または私が何をしようとしているのか本当に疑問に思っている人)のために、私たちがやろうとしているのは、Rhino.Commonsのラッパーを作成することです。 .NHRepositoryは、開発者のグループに公開したくないメソッドを非表示にするため、新しい開発者が簡単にフォローできるアプリを開発するための型抜きの方法を使用できます。そうです、「Is-A」テストはチェーン全体に有効だと思います(WidgetRepository Is-A BaseRepository Is-A NHRepository)。

編集:議論のために、クラスAは私たちの制御の及ばないAPIクラスであると述べるべきでした。そうしないと、問題がかなり簡単になります。

17
Ogre Psalm33

それを実行して階層を保持することはできません。可能であれば、理想を定義するインターフェースを作成してから、基本クラスをサブクラス化し、インターフェースを実装する必要があります。コード内で(基本クラスタイプではなく)インターフェイスのみを参照します。

Adapter pattern は、APIがニーズに正確に一致しない場合にフレームワークを使用する方法の問題を解決するために特別に作成されました。

21
Michael Meadows

廃止されました

クラスBで、MethodToHideをオーバーライドし、Obsolete属性を追加します

[Obsolete("Reason", true)] // true will cause a compile-time error

Set EditorBrowsable

(前述のとおり)

クラスBで、MethodToHideをオーバーライドし、EditorBrowsable属性を追加します

[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]

例外をスローします

(前述のとおり)

クラスBで、MethodToHideをオーバーライドし、例外をスローします。

ラッパーの作成

マイケルメドウズは正しいと思います。 アダプタパターン を使用します。このパターンにより、単体テスト時にコードを簡単にモックすることもできます。

class B: IInterface
{    
    protected void MethodToExpose()
    {
        A a = new A();
        a.MethodToExpose();
    }

    protected void NewMethodInB()
    {
    }
}
19
Monkey Code

機能のセットをカスタム調整したい場合は、機能を継承するのではなく、ラッパーを作成したいと思います。 C#でやりたいことをする方法もわかりません。

考えてみてください。コントロール外のコードが何かのためにこのNHRepositoryインスタンスを必要としている場合はどうでしょうか...しかし、子クラスで必要な関数から機能を削除しました(これは、送信するためです。あなたの唯一のNHRepositoryインスタンス。)すべてがブームになります。だから、醜いハックなしではできないと思います。

14
Blixt

Visual Studioを使用している場合は、次の属性を使用して、メソッド/プロパティをintellipromptから非表示にできます。

class A
{
    protected void MethodToExpose()
    {}

    [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
    protected void MethodToHide(object param)
    {}
}

それは実際には機能を取り除くことはありませんが、彼らがあなたの内部の人々である場合。十分近いかもしれません。

6
Jake Pearson

私の意見では、それを行う最良の方法は、新しい機能を実際にオーバーライドして外部化するのではなく、非表示にしたい場合は、EditorBrowsableState属性を追加することです。 VisualStudioエディターでメソッドを非表示にします。誰がそれを使おうとすると、コンパイル時エラーが発生します。

メソッドの上に次のコードを追加するだけです。

[System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]

例えば

public class User
{        
    public void DoSomething()
    {
       Something...
    }
}

public class Manager
{
    [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
    public override void DoSomething()
    { }
}

void main()
{
   User user = new User();
   user.DoSomething();

   Manager manager = new Manager();
   manager.DoSomething(); // --------- This row will throw a design time error
}

幸運を :)

4
Guy Levin

実際、BのメソッドをCからアクセス可能として定義した場合は、AのメソッドをCから隠すことができます。

コードの唯一の問題は、非表示宣言で「プライベート」を使用することです...プロテクトまたはパブリックを使用する場合、問題は発生せず、期待どおりに動作します。私はこれを常にフィールドで行います。

1
KDogg

C#には、C++の保護継承またはプライベート継承に似た概念はありません。

最善のオプションは、クラスのインスタンスを集約し、コンシューマーがアクセスできることに関心のあるメソッドのセットを公開することです。

あなたの場合は不可能だと思いますが、コンシューマーに使用してもらいたい一般的な機能だけを公開するインターフェースを作成して、ラッパーを集約の代わりに使用できるようにすることもできます。

1
LBushkin

私はC++についてあまり知りませんが、C++でそれができるとは知りませんでした。 ラッパークラスがおそらくこれを実装する方法であるというBlixtに同意するのではないかと思います。

単純に関数をオーバーライドするそして呼び出し時に例外をスローすることはうまくいくかもしれません(しかし私にはわかりません)。

1
Frank V

私の知る限り、あなたはそれをあなたが望む方法で隠すことはできません。ただし、実際的な方法での使用を防ぐことができると思います。

class B : A
{
    public new void MethodToHide(object param)
    { 
        throw new DontUseThisMethodException();
    }

    protected void NewMethodInB()
    {}
}

しかし、最も良いことではないので、おそらく他の方法でそれを解決したいと思うでしょう...

1
Fredrik Mörk

派生クラスBのコードは、基本メソッドをすべての派生型から非表示にするのではなく、それ自体のみを非表示にします。ベースでメソッドをprivateに設定する必要があります。この問題を回避する唯一の方法は、このメソッドを公開しない別の基本クラスを作成することです。

0
James