C# 避免使用字典中的DynamicVoke()<;类型、委托>;
我有一种MessageBroker类,它在运行时将传入的消息类型映射到处理程序方法。在处理程序中维护强类型消息对我来说很重要。它的工作原理是查找从C# 避免使用字典中的DynamicVoke()<;类型、委托>;,c#,reflection,delegates,C#,Reflection,Delegates,我有一种MessageBroker类,它在运行时将传入的消息类型映射到处理程序方法。在处理程序中维护强类型消息对我来说很重要。它的工作原理是查找从IMessage继承的所有类,并创建一个Delegate,以调用任何具有Handles(TMessage)属性的方法,其中TMessage与传入的IMessage基础类型匹配 因此,“处理程序”如下所示: [Handles(typeof(TestMessage))] public void HandleTestMessage(objectsender,
IMessage
继承的所有类,并创建一个Delegate
,以调用任何具有Handles(TMessage)
属性的方法,其中TMessage
与传入的IMessage
基础类型
匹配
因此,“处理程序”如下所示:
[Handles(typeof(TestMessage))]
public void HandleTestMessage(objectsender, TestMessage request)
{
var response = new TestResponse() { TestInt = request.TestInt };
msgService.Send(sender, response);
}
同样,我真的希望避免在方法签名中使用IMessage
,对我来说,不必在方法体中强制转换IMessage
,这一点很重要
broker类使用以下方法来发现和注册处理程序:
/// <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);
}
}
当我将MethodInfo
s转换为Delegate
s(Action
或Func
)时,我认为我是聪明的,但我忽略了检查在调用上使用DynamicInvoke
的含义。事实证明,DynamicInvoke
会产生相对较大的开销。因此,我的问题是,如何将处理程序Delegate
s视为实际的Delegate
s(同样,Action或Func)
如您所见,在HandleMessage
中,我确实知道消息的基本类型,并且发送者始终是一个对象。基本上,我需要做一些事情,比如:
((操作)处理程序)。调用(发送方、消息)代码>
显然这是不可能的,但它清楚地说明了我正在努力实现的目标(我认为)
我尝试创建一种介于两者之间的通用方法:
public void InvokeHandler<TMessage>(Action<object, TMessage> handler, TMessage message, object sender = null)
public void InvokeHandler(操作处理程序,TMessage消息,object sender=null)
但我在尝试调用此方法时遇到了相反的问题。此代码中的括号和/或尖括号不匹配(或者我的眼睛会:((Action@Flydog57是的,你是对的。我修复了它。你修复了上面的代码,还是解决了你的问题?如果你有MethodInfos,通过它们直接调用要比通过委托调用慢一些(如果我没记错的话,我10多年前就研究过这个问题),但速度仍然相当快;肯定比DynamicInvoke快。您可以通过反射创建一个动作对象,然后(通过反射)调用它,但是(猜测)它可能不会比DynamicInvoke快。我构建的工作类型半定期地使用MethodInfos做事情(尽管我已经停止检查它们的速度)。
public void InvokeHandler<TMessage>(Action<object, TMessage> handler, TMessage message, object sender = null)