我有一个实现
的类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)并被调用。
更新:所以上面的代码是正确的,应该可行。在我的程序中,我只是输错了,并且在错误的对象上调用该方法。
答案 0 :(得分:1)
在评论的帮助下解决。 我创建了一个单独的最小复制器,它工作。然后检查了原始代码,发现了一个错字。所以基本思想从一开始就是正确的。
答案 1 :(得分: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;
}
}