2

概念実証として単純な「バス」を構築しています。複雑なことは何も必要ありませんが、次のコードを最適化する方法を考えています。コマンドをオープン ジェネリックとして解決するためのコンテナーとして Autofac を使用していますが、実際にコマンドを実行することは現在、リフレクションを介して行われています。コードを参照 - // BEGIN // END でマークアップ - これは現在リフレクションで行われています。リフレクションを使用せずにこれを行う方法はありますか?

// IoC wrapper
static class IoC {
    public static object Resolve(Type t) {
        // container gubbins - not relevant to rest of code.
    }
}

// Handler interface
interface IHandles<T> {
    void Handle(T command);
}

// Command interface
interface ICommand {
}

// Bus interface
interface IBus {
    void Publish(ICommand cmd);
}

// Handler implementation
class ConcreteHandlerImpl : IHandles<HelloCommand> {
    public void Handle(HelloCommand cmd) {
        Console.WriteLine("Hello Command executed");
    }
}

// Bus implementation
class BusImpl : IBus {
    public void Publish(ICommand cmd) {
        var cmdType = cmd.GetType();
        var handler = IoC.Resolve(typeof(IHandles<>).MakeGenericType(cmdType));
        // BEGIN SLOW
        var method = handler.GetType().GetMethod("Handle", new [] { cmdType });
        method.Invoke(handler, new[] { cmd });
        // END SLOW
    }
}
4

2 に答える 2

5

これはどうですか(変更された部分のみを示します):-

// Handler interface
interface IHandles<T> where T : ICommand {
    void Handle(T command);
}

// Bus interface
interface IBus {
    void Publish<T>(T cmd) where T : ICommand;
}

// Bus implementation
class BusImpl : IBus {
    public void Publish<T>(T cmd) where T : ICommand {
        var handler = (IHandles<T>)IoC.Resolve(typeof(IHandles<T>));
        handler.Handle(cmd);
    }
}

ここで重要なのは、Publishメソッドをジェネリックにすることです。つまりT、コマンドの型への型参照を取得し、それを使用してキャストを行うことができます。ICommand型パラメーターの制約は、以前と同様に、 an のみが渡されることを保証するだけです。

ところで-私はこれをテストしましたが、動作します。完全なコードは次のとおりです:-

public static void Main(){
   new BusImpl().Publish(new HelloCommand());
}

// IoC wrapper
static class IoC {
    public static object Resolve(Type t) {
        return new ConcreteHandlerImpl();
    }
}

// Handler interface
interface IHandles<T> where T : ICommand {
    void Handle(T command);
}

// Command interface
interface ICommand {
}


// Handler implementation
class ConcreteHandlerImpl : IHandles<HelloCommand> {
    public void Handle(HelloCommand cmd) {
        Console.WriteLine("Hello Command executed");
    }
}

public class HelloCommand:ICommand{}

// Bus interface
interface IBus {
    void Publish<T>(T cmd) where T : ICommand;
}

// Bus implementation
class BusImpl : IBus {
    public void Publish<T>(T cmd) where T : ICommand {
        var handler = (IHandles<T>)IoC.Resolve(typeof(IHandles<T>));
        handler.Handle(cmd);
    }
}

- アップデート -

Peter Lillevold が指摘したように、次のように IOC コンテナー メソッドに型パラメーターを追加することも検討する必要があります。

// IoC wrapper
static class IoC {
    public static T Resolve<T>() {
        ...
    }
}

これにより、呼び出し元が次のように簡素化されます:-

// Bus implementation
class BusImpl : IBus {
    public void Publish<T>(T cmd) where T : ICommand {
        var handler = IoC.Resolve<IHandles<T>>();
        handler.Handle(cmd);
    }
}

これは元の質問の補足ですが、IOC インターフェイスの賢明な設計と思われます。

于 2011-10-15T13:56:40.447 に答える
0

これは機能しますか?IoC はオブジェクトを返します。代わりに T を返すことを検討してください。そうすれば、以下で行うように型のあいまいさを処理する必要がなくなります。

public void Publish(ICommand cmd) {
    var cmdType = cmd.GetType();
    var handler = IoC.Resolve(typeof(IHandles<>).MakeGenericType(cmdType)) as IHandles<ICommand>;
    if (handler != null)
    {
        // BEGIN SLOW
        handler.Handle(command);
        // END SLOW
    }
    //else throw some exception
}
于 2011-10-15T13:14:39.277 に答える