web-dev-qa-db-ja.com

インターフェース実装としてのC#拡張メソッド

あるクラスのC#拡張メソッドがインターフェイスの実装として機能できるかどうか疑問に思っていましたか?私が持っているもの:

インターフェース:

public interface IEventHandler
{
    void Notify(SEvent ev, IEventEmmiter source);
}

それを実装するクラス:

class Sim : IEventHandler
{

    /*public void Notify(SEvent ev, IEventEmmiter source)
    {
        Console.WriteLine("Got notified: " + ev.Name);
    }*/

}

そして、拡張メソッドを含むクラス:

public static class ReflectiveEventDispatcher
{
    public static void Notify(this IEventHandler handler, SEvent ev)
    {
        if (handler.GetType().GetMethod("Handle" + ev.Name) != null)
        {
            // C# WTF?
            object[] prms = new object[0];
            prms[0] = ev;
            handler.GetType().GetMethod("Handle" + ev.Name).Invoke(handler, prms);
        }
        else
        {
            throw new System.NotImplementedException("This object doesn't have appropriate handler methods for event " + ev.Name);
        }
    }
}

ここで、IEventHandlerインターフェイスを備えたさまざまなクラスを作成し、インターフェイスの実装を拡張メソッドで実行する必要があります。

それが不可能な場合、Notifyを明示的に定義して、呼び出しを拡張メソッドに転送することは可能ですか?

上記のコードは基本的に多重継承ハックです。他の方法でこの動作をエミュレートすることは可能ですか?

(これが理にかなっているといいのですが、私はRubyに慣れています。これは本当に私に苦労します。ああ、あなたがいなくて寂しいです、私の愛するミックスイン...)

更新

電話転送はそれをかなりよく解決しました:

public void Notify(SEvent ev)
{
    ReflectiveEventDispatcher.Notify(this, ev,);
}
45
PJK

これは、説明する方法では実行できません。C#メソッド呼び出しの解決では、常にメソッドの具体的な実装が選択され、拡張メソッドは選択されません。

ただし、インターフェイスでメソッドを定義せずに、単に異なる名前空間の拡張メソッドとして定義すれば、必要なものをある程度取得できると思います。もちろん、これは「静的」であり、呼び出されるメソッドはコンパイル時に選択されます。

実際には、適切な "using"ディレクティブを介して呼び出されるメソッドを選択します(LINQの動作と同様)。

14
jeroenh

いいえ、拡張メソッドはインターフェースの実装として機能できません。拡張メソッドは、そのクラスのインスタンスを最初のパラメーターとして受け取る静的メソッドの構文糖衣であり、特定のクラスのメンバーではないため、インターフェースを実装するための要件です。

27
Femaref

これは不可能です。

インターフェイスメソッドは、実装型自体によって実装する必要があります。

拡張メソッドは純粋に言語レベルの概念(構文糖衣)であり、役に立ちません。 CLR自体は、拡張メソッドを完全に認識していません。

9
SLaks
var sim = new Sim()
((IEventHandler )sim).Notify(ev)
1
Andrej Kaurin