避免从Dictionary <type,proxy =“”>

时间:2018-07-10 19:15:23

标签: c# reflection delegates

我有一种消息代理类,可在运行时将传入的消息类型映射到处理程序方法。对我而言,在处理程序中维护强类型消息非常重要。它的工作原理是找到所有从IMessage继承的类,并创建一个Delegate来调用任何具有Handles(TMessage)属性的方法,其中TMessage与传入的{{1 }}基础IMessage

因此,“处理程序”如下所示:

Type

同样,我真的很想避免在方法签名中使用[Handles(typeof(TestMessage))] public void HandleTestMessage(objectsender, TestMessage request) { var response = new TestResponse() { TestInt = request.TestInt }; msgService.Send(sender, response); } ,对于我来说,不必在方法主体中强制转换IMessage至关重要。

broker类使用以下方法发现并注册处理程序:

IMessage

最后,当收到消息时,它使用此方法来调用(/// <summary> /// Subscribes all methods with the <see cref="HandlesAttribute"/> to the given <see cref="IMessage"/> <see cref="Type"/> /// </summary> /// <param name="target">The object to inspect</param> public void SubscribeAll(object target) { var targetType = target.GetType(); // Get all private and public methods. var methods = targetType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); foreach (var method in methods) { // If this method doesn't have the Handles attribute then ignore it. var handlesAttributes = (HandlesAttribute[])method.GetCustomAttributes(typeof(HandlesAttribute), false); if (handlesAttributes.Length != 1) continue; // The method must have only 2 arguments. var parameters = method.GetParameters(); if (parameters.Length != 2) { log.LogDebug(string.Format("Method {0} has too many arguments", method.Name)); continue; } // The second argument must be derived from IMessage. if (!typeof(IMessage).IsAssignableFrom(parameters[1].ParameterType)) { log.LogDebug(string.Format("Method {0} does not have an IMessage as it's second argument", method.Name)); continue; } Type genericDelegate; if(method.ReturnType == typeof(void)) { genericDelegate = typeof(Action<,>).MakeGenericType(parameters[0].ParameterType, handlesAttributes[0].MessageType); } else { genericDelegate = typeof(Func<,,>).MakeGenericType(parameters[0].ParameterType, handlesAttributes[0].MessageType, method.ReturnType); } var handler = method.CreateDelegate(genericDelegate, target); // Success, so register! Subscribe( handlesAttributes[0].MessageType, handler); } } )处理程序:

DynamicInvoke

当我将/// <summary> /// Passes a given <see cref="IMessage"/> and optional sender to any <see cref="Handler"/>s accepting the message's underlying type /// </summary> /// <param name="message">The <see cref="IMessage"/> to send</param> /// <param name="sender">The original sender of the message</param> private void HandleMessage(IMessage message, object sender = null) { var messageType = message.GetType(); if (messageHandlers.TryGetValue(messageType, out List<Delegate> handlers)) { foreach (var handler in handlers) { handler.DynamicInvoke(new object[] { sender, message }); } } else { log.LogError(string.Format("No handler found for message of type {0}", messageType.FullName)); throw new NoHandlersException(); } } 转换为MethodInfoDelegateAction<,>)时,我以为自己很聪明,但是我忽略了使用{{ 1}}超过Func<,,>。事实证明DynamicInvoke产生了相当大的开销。所以我的问题是,如何将处理程序Invoke当作它们是 actual DynamicInvoke(再次是Action <,>或Func <,,>)

如您所见,在Delegate中,我知道知道Delegate的基础类型,并且发件人始终是对象。基本上,我需要做类似的事情:

HandleMessage

显然这是不可能的,但它说明了我正在努力实现的目标(我认为)。

我尝试创建一种介于两者之间的通用方法:

message

但是在尝试调用此方法时,我只是碰到了底线问题。

0 个答案:

没有答案