【问题标题】:Pass a Func<T> into generic method via reflection [closed]通过反射将 Func<T> 传递给泛型方法[关闭]
【发布时间】:2012-12-07 11:43:33
【问题描述】:

我有一个实现的类

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) 并被调用。

更新:所以上面的代码是正确的并且应该可以工作。在我的程序中,我只是有一个错字,并且在错误的对象上调用了该方法。

【问题讨论】:

  • 您正在找到第一个带有 two 参数的方法...但您的方法只有 one 参数...您能发布一个简短的但是完整的程序能说明问题吗?
  • 乔恩,这是一个错字。是的,真正的方法有 2 个参数,但没关系。我很快就会写一个完整的工作复制器。
  • 修复错别字后(我认为Length == 2 应该是Length == 1Message1 应该是MessageA)当我尝试它时它编译并运行没有错误。您能否向我们展示一个出错的最小示例?
  • 我找到了问题的原因。这是非常愚蠢的。我正在调用 subscribeConcrete.Invoke(mbt) 而不是 subscribeConcrete.Invoke(mb)。很公平,它正在抛出:)
  • @VladimirPerevalov 这就是为什么我更喜欢长变量名的原因。 :) 顺便说一句,回答您自己的问题,以便其他读者可以找出导致此问题的原因。

标签: c# generics reflection delegates


【解决方案1】:

在 cmets 的帮助下解决了。 我创建了一个单独的最小复制器并且它工作。然后检查原始代码,发现一个错字。所以基本思路从一开始就是正确的。

【讨论】:

    【解决方案2】:

    您可能正在寻找这样的东西:

    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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-15
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多