web-dev-qa-db-ja.com

インターフェースで宣言されたメソッド実装をオーバーライドする

私はそれにいくつかのメソッドを持つインターフェースを持っています。

_interface IMyInterface
{
    //...
    void OnItemClicked()
    //...
}
_

そして実装

_class MyClass : IMyInterface
{
    //Other methods
    public void OnItemClicked(){ /*...*/ } 
}
_

ここで、OnItemClicked()以外はMyClassのように動作するクラスが必要です。このメソッドにいくつかの変更を加えます。

オーバーライドを継承することを考えましたが、MyClassを変更したくありません(例:public virtual void OnItemClicked()...)。実装、

OnItemClicked()は変更するMyClassの唯一の部分であるため、再度IMyInterfaceを実装したくありません。

他に方法はありますか?

16
Miklós Balogh

あなたがインターフェースを実装しているので、多態性はおそらくあなたが保持したいものです。基本クラスを仮想で変更せずにメソッドをオーバーライドすることは不可能であるため、Tigranが書いたように、仮想の代わりにnewを使用する必要があります。

つまり、この種のコードを記述しても、メソッドの基本バージョンのみが実行されます。

List<MyClass> aList = new List<MyClass>();
aList.Add(new MyClass());
aList.Add(new MyNewClass());
foreach (MyClass anItem in aList)
    anItem.OnItemClicked();

適切なコードを実行するには、次のような醜いコードを書く必要があります。

List<MyClass> aList = new List<MyClass>();
aList.Add(new MyClass());
aList.Add(new MyNewClass());
foreach (MyClass anItem in aList)
{
    MyNewClass castItem = anItem as MyNewClass;
    if (castItem != null)
        castItem.OnItemClicked();
    else
        anItem.OnItemClicked();
}

とにかく、IMyInterfaceとして宣言された変数に割り当てられたときに、クラスが適切なメソッドを実行する方法があります。先に進むには、オーバーライドするインターフェイスの部分を明示的に実装します。この場合はOnItemClickedメソッドです。コードは次のとおりです。

public class MyNewClass : MyClass, IMyInterface // you MUST explicitly say that your class implements the interface, even if it's derived from MyClass
{
    public new void OnItemClicked() //NEW keyword here you have the overridden stuff
    { 
        /*...*/ 
    } 

    void IMyInterface.OnItemClicked() // No need for public here (all interfaces's methods must be public)
    { 
        this.OnItemClicked(); 
    } 
}

この方法では:

 MyClass cl = new MyNewClass(); 
 cl.OnItemClicked();

基本メソッドを実行します

 MyNewClass cl = new MyNewClass(); 
 cl.OnItemClicked();

派生クラスのメソッドを実行します

 IMyInterface cl = new MyNewClass(); 
 cl.OnItemClicked();

派生クラスのメソッドを実行し、実行時にバインドされます。つまり、私の最初の例のコードを次のように記述し、適切なメソッドを実行させることができます。

List<IMyInterface> aList = new List<IMyInterface>();
aList.Add(new MyClass());
aList.Add(new MyNewClass());
foreach (IMyInterface anItem in aList)
    anItem.OnItemClicked();
17

MyClassから派生できます

public class MyNewClass : MyClass
{
    public new void OnItemClicked(){ /*...*/ } //NEW keyword
}

唯一のことは、この方法で多態性をサポートしないことに注意してください。

より明確にするために:

     MyClass cl = new MyNewClass(); 
     cl. MyMethod();

realオブジェクトタイプがMyClassであっても、これはMyNewTypeメソッドを呼び出します。私たちが望むものを呼び出すことができるようにするには、型を明示的に定義する必要があります

     MyNewClass cl = new MyNewClass(); 
     cl. MyMethod(); //WILL CALL METHOD WE WANT
5
Tigran

最も簡単な方法は、「has-a」を使用して「is-a」を模倣する新しいクラスを作成することです。

public interface IMyInterface
{
    void OnItemClicked();
    void OnItemHover();
    void OnItemDoubleClicked();
}

public class MyNewClass : IMyInterface
{
    private IMyInterface _target;

    public MyNewClass(IMyInterface target)
    {
        _target = target;
    }

    public void OnItemClicked()
    {
        // custom functionality
    }

    public void OnItemHover()
    {
        _target.OnItemHover();
    }

    public void OnItemDoubleClicked()
    {
        _target.OnItemDoubleClicked();
    }
}
3
armen.shimoon

パターンブリッジを使用 http://en.wikipedia.org/wiki/Bridge_pattern

1
burning_LEGION