2

私が探しているものの短いバージョンはこれです:

私は、インターフェイスが与えられると、そのインターフェイスのクラスのペア、1つのマルチプレクサと1つのデマルチプレクサを動的に生成するメカニズムを探しています。これにより、次の形式の汎用デリゲートとの間で呼び出しが変換されますobject AnyCall( int method_selector, object[] arguments )。マルチプレクサクラスは、構築時パラメータとしてAnyCallデリゲートを受け入れ、デリゲートへのすべての呼び出しを委任することによってインターフェイスを実装します。デマルチプレクサクラスは、構築時パラメータとしてインターフェイスへの参照を受け入れ、メソッドセレクタをオンにしてインターフェイスの適切なメソッドを呼び出し、デリゲートに渡されたパラメータを渡すことで、デリゲートを実装します。

私が探しているものの長いバージョンはこれです:

次のインターフェイスについて考えてみます。

public interface IFooable
{
    void Moo( int i );
    void Boo( string s, bool b );
}

そして、そのインターフェースを実装する次のクラスを検討してください。

public class FooImplementation: IFooable
{
    void IFooable.Moo( int i ) { System.Console.WriteLine( "i: " + i ); }
    void IFooable.Boo( string s, bool b ) { System.Console.WriteLine( "s: " + s + ", b: " + b );  }
}

次に、上記を利用して次のクラスを検討します。

public partial class MuxdemTest
{
    public static void InvokeFoo( IFooable fooable )
    {
        fooable.Moo( 42 );
        fooable.Boo( "fubar!", true );
    }

    public static void Run1()
    {
        IFooable fooable = new FooImplementation();
        InvokeFoo( fooable );
    }
}

ここには何も派手なものはありません。

ここで、InvokeFoo()にFooImplementationへの直接参照を与える代わりに、2つの間にいくつかの機能を埋め込み、インターフェイスメソッド呼び出しでいくつかの本当に便利なことを実行できるようにしたいとします。インターフェイスのメソッドの1つが呼び出された回数。または、呼び出しをメッセージに変換して、別のスレッドにあるFooImplementationに配信します。または別の大陸で; または何でも。そしてもちろん、この中間の機能は、IFooableだけでなく、どのインターフェイスでも機能するはずです。

これを実現するには、インターフェイスのメソッドへの呼び出しを単一の汎用デリゲートの呼び出しに多重化し、後でそのデリゲートへの呼び出しからインターフェイスのメソッド呼び出しに逆多重化する方法が必要です。私が考えている代表者は、次の形式になります。

public delegate object AnyCall( int method_selector, object[] arguments );

したがって、IFooableインターフェイス用のマルチプレクサの実装は次のとおりです。

public class MuxForFooable: IFooable
{
    private readonly AnyCall AnyCall;
    public MuxForFooable( AnyCall anycall ) { AnyCall = anycall; }
    void IFooable.Moo( int i ) { AnyCall( 0, new object[]{ i } ); }
    void IFooable.Boo( string s, bool b ) { AnyCall( 1, new object[]{ s, b } ); }
}

そして、これがIFooableインターフェース用のデマルチプレクサの実装です。

public class DemuxForFooable
{
    public readonly IFooable Target;
    public DemuxForFooable( IFooable target ) { Target = target; }
    public object AnyCall( int method_selector, object[] arguments )
    {
        switch( method_selector )
        {
            case 0: Target.Moo( (int)arguments[0] ); break;
            case 1: Target.Boo( (string)arguments[0], (bool)arguments[1] ); break;
            default: throw new System.InvalidOperationException();
        }
        return null;
    }
}

上記を利用して、上記のRun1()メソッドとまったく同じことを実現するコードを次に示します。違いは、すべての呼び出しが「AnyCall」デリゲートを通過することです。

public partial class MuxdemTest
{
    public static void Run2()
    {
        IFooable fooable = new FooImplementation();
        DemuxForFooable demux = new DemuxForFooable( fooable );
        MuxForFooable mux = new MuxForFooable( demux.AnyCall );
        InvokeFoo( mux );
    }
}

私の唯一の問題は、クラスMuxForFooableとDemuxForFooableが手書きされているのに、動的に生成したいということです。それらを生成する次のモックメソッドと、それらのメソッドを使用するコードを検討してください。

public partial class MuxdemTest
{
    public static T CreateMux<T>( AnyCall anycall )
    {
        if( typeof(T) == typeof(IFooable) )
            return (T)(IFooable)new MuxForFooable( anycall );
        throw new System.NotImplementedException();
    }

    public static AnyCall CreateDemux<T>( T target )
    {
        if( typeof(T) == typeof(IFooable) )
            return new DemuxForFooable( (IFooable)target ).AnyCall;
        throw new System.NotImplementedException();
    }

    public static void Run3()
    {
        IFooable fooable = new FooImplementation();
        AnyCall demux = CreateDemux<IFooable>( fooable );
        IFooable mux = CreateMux<IFooable>( demux );
        InvokeFoo( mux );
    }
}

上記のRun3()は、上記のRun2()およびRun1()とまったく同じ効果があります。

では、CreateMux()とCreateDemux()の実際の実装を作成したり、作成する方法を知っている人はいますか?

インターフェイスにはメソッドのみが含まれ、プロパティは含まれず、すべてのメソッドはvoidを返し、「ref」パラメータや「out」パラメータを受け入れないと想定できます。(私はこれらのことを可能にする実装を気にしませんが。)

私がやりたいことと同じようなことをするコードサンプルはたくさんありますが、動的コード生成の主題は非常にトリッキーなので、誰かが私がやりたいことをすでに正確に行っていることを期待して、この質問を投稿しています。

CastleProxyのような既存のプロキシフレームワークで何ができるかはわかっていますが、このような単純なタスクに外部フレームワーク全体を使用したり、そのようなフレームワークを使用することで実行時のオーバーヘッドが発生したりすることは望んでいません。CastleProxyのソースコードを見て、その一部を使用して自分のやりたいことを実行する方法を見つけようとしましたが、複雑すぎて意味がわかりませんでした。

編集1:

6か月後、私はこの質問で求めていたことを実行するツールを実装しました。私はそれについての論文を発表するつもりですが、それをする前に、私はネーミングの助けが必要なので、私は別の質問を開きました:ネーミングの助けが必要です(インターフェース呼び出しのマーシャリング)

それまでの間、回答があればお気軽に追加してください。

編集2:

私はこのツールを「絡み合う」と呼び、操作を「絡み合わせる」「巻き戻し」と呼ぶことにしました。それについて読みたい場合は、ここにあります:michael.gr-絡み合う:インターフェイス呼び出しの正規化

4

2 に答える 2

1

これを実現するには、インターフェイスのメソッドへの呼び出しを単一の汎用デリゲートの呼び出しに多重化し、後でそのデリゲートへの呼び出しからインターフェイス メソッド呼び出しに逆多重化する方法が必要です。

これがあなたの要件からどのように続くかわかりません。あなたが実際に欲しいのはDynamixProxy、またはそれに似たものだと思います。これを使用すると、メソッドの呼び出しをインターセプトできます。これはまさにあなたが望むものと思われます。簡単な例:

class LoggingIntereceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine(invocation.Method);
        invocation.Proceed();
    }
}

…

public static void Run1()
{
    var generator = new ProxyGenerator();
    IFooable fooable = generator.CreateInterfaceProxyWithTarget<IFooable>(
        new FooImplementation(), new LoggingIntereceptor());
    InvokeFoo(fooable);
}

これにより、次の出力が得られます。

Void Moo(Int32)
i: 42
Void Boo(System.String, Boolean)
s: fubar!, b: True

DynamicProxy は、実行時にインターフェイスを実装する型を生成するため、非常に高速です。

プロジェクトに「フレームワーク全体」を追加したくない場合は、その必要はありません。上記の例を実行するために必要なのは、Castle.Core.dll という 1 つの追加アセンブリだけです。

于 2011-05-27T19:10:29.177 に答える