refactor: Reduce reflection calls when using HandlerInvoker (#5241)

Changes `HandlerInvoker` to avoid reflecting for every message when handling arity=2 `IHandler<,>` instances, by moving it out of the final generated delegate.
This commit is contained in:
Jacob Alber 2025-01-28 16:17:11 -05:00 committed by GitHub
parent e6926352aa
commit 2e83d7244a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 9 additions and 10 deletions

View File

@ -70,9 +70,10 @@ public abstract class BaseAgent : IAgent, IHostableAgent
Dictionary<Type, HandlerInvoker> invokers = new();
foreach (Type interface_ in candidateInterfaces)
{
MethodInfo? maybeHandle = interface_.GetMethod(nameof(IHandle<object>.HandleAsync), BindingFlags.Instance | BindingFlags.Public);
MethodInfo handleAsync = interface_.GetMethod(nameof(IHandle<object>.HandleAsync), BindingFlags.Instance | BindingFlags.Public)
?? throw new InvalidOperationException($"No handler method found for interface {interface_.FullName}");
HandlerInvoker invoker = new(maybeHandle ?? throw new InvalidOperationException($"No handler method found for interface {interface_.FullName}"), this);
HandlerInvoker invoker = new(handleAsync, this);
invokers.Add(interface_.GetGenericArguments()[0], invoker);
}

View File

@ -42,19 +42,17 @@ public class HandlerInvoker
return null;
};
}
else if (
methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)
)
else if (methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>))
{
MethodInfo typeEraseAwait = typeof(HandlerInvoker)
.GetMethod(nameof(TypeEraseAwait), BindingFlags.NonPublic | BindingFlags.Static)!
.MakeGenericMethod(methodInfo.ReturnType.GetGenericArguments()[0]);
getResultAsync = async
(object? message, MessageContext messageContext) =>
{
object valueTask = invocation(message, messageContext)!;
object? typelessValueTask = typeof(HandlerInvoker)
.GetMethod(nameof(TypeEraseAwait), BindingFlags.NonPublic | BindingFlags.Static)!
.MakeGenericMethod(methodInfo.ReturnType.GetGenericArguments()[0])
.Invoke(null, new object[] { valueTask });
object? typelessValueTask = typeEraseAwait.Invoke(null, new object[] { valueTask });
Debug.Assert(typelessValueTask is ValueTask<object?>);