0

実装するクラスがあります

class MessageBus
{
    void Subscribe<T>(Func<T,Task> onMessage) {...}
}

私のコードでは、いくつかの異なるメッセージタイプで動的にサブスクライブしたいと思います。たとえば、メッセージタイプは次のとおりです。

class Message {}
class MessageA : Message {}
class MessageB : Message {}

私はこれに似たコードを書きます:

class MySubscriber
{
    void Initialize()
    {
         var mb = new MessageBus();
         var mbt = mb.GetType();
         var subscribeGeneric = mbt.GetMethods().First(x => x.Name == "Subscribe" && x.GetParameters().Length == 1);

         var subscribeConcrete = subscribeGeneric.MakeGenericMethod(typeof(Message1));
         subscribeConcrete.Invoke(mb, new object[]{ new Func<Message1,Task>(Handle) });
         // On this line I get exception TargetException("Type does not meet target type"). Message my be a bit different, on my system I see it in Russian.
    }
    Task Handle(Message msg) {}    
}

もちろん、この例では、リフレクションを介して呼び出すことは意味がありませんが、実際のプログラムでは、typeof(Message1)を動的に取得し、それらの型の配列を取得します。私は何が間違っているのですか?すべて同じように正常に書き込むと、動作します(つまり、Handle(Message)がHandle(Message1)に正常にキャストされ、呼び出されます。

更新:上記のコードは正しく、機能するはずです。私のプログラムでは、単にタイプミスがあり、間違ったオブジェクトでメソッドを呼び出していました。

4

2 に答える 2

1

コメントの助けを借りて解決しました。別の最小限の再生装置を作成しましたが、機能しました。次に、元のコードを調べて、タイプミスを見つけました。したがって、基本的な考え方は最初から正しかった。

于 2012-12-07T15:11:52.983 に答える
0

あなたはこのようなものを探しているかもしれません:

public class Dispatcher<TTarget,TArgBase>
{
    private Dictionary<Type, Action<TTarget, TArgBase>> _handlers;

    public Dispatcher(string methodName)
    {
        _handlers = typeof(TTarget).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
            .Where(m => m.Name == methodName)
            .Where(m => m.ReturnType == typeof(void))
            .Where(m => !m.ContainsGenericParameters)
            .Where(m =>
            {
                var pars = m.GetParameters();
                return pars.Length == 1 && typeof(TArgBase).IsAssignableFrom(pars[0].ParameterType);
            })
            .ToDictionary(m => m.GetParameters()[0].ParameterType, m => BuildWrapper(m));
    }

    private static Action<TTarget, TArgBase> BuildWrapper(MethodInfo m)
    {
        var target = Expression.Parameter(typeof(TTarget), "target");
        var dest = Expression.Parameter(typeof(TArgBase), "destination");
        var castEvent = Expression.TypeAs(dest, m.GetParameters()[0].ParameterType);
        var call = Expression.Call(target, m, castEvent);
        return Expression.Lambda<Action<TTarget, TArgBase>>(call, target, dest).Compile();
    }

    public bool Call(TTarget target, TArgBase evt)
    {
        Action<TTarget, TArgBase> handler;
        _handlers.TryGetValue(evt.GetType(), out handler);
        if(handler == null)
            return false;
        handler(target, evt);
        return true;
    }
}
于 2012-12-07T14:00:28.687 に答える