From 2e83d7244afb1c1c85ccee7672fadf2e2e31fe4e Mon Sep 17 00:00:00 2001 From: Jacob Alber Date: Tue, 28 Jan 2025 16:17:11 -0500 Subject: [PATCH] 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. --- dotnet/src/Microsoft.AutoGen/Core/BaseAgent.cs | 5 +++-- .../src/Microsoft.AutoGen/Core/HandlerInvoker.cs | 14 ++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/dotnet/src/Microsoft.AutoGen/Core/BaseAgent.cs b/dotnet/src/Microsoft.AutoGen/Core/BaseAgent.cs index f63199cd8..99ff001ba 100644 --- a/dotnet/src/Microsoft.AutoGen/Core/BaseAgent.cs +++ b/dotnet/src/Microsoft.AutoGen/Core/BaseAgent.cs @@ -70,9 +70,10 @@ public abstract class BaseAgent : IAgent, IHostableAgent Dictionary invokers = new(); foreach (Type interface_ in candidateInterfaces) { - MethodInfo? maybeHandle = interface_.GetMethod(nameof(IHandle.HandleAsync), BindingFlags.Instance | BindingFlags.Public); + MethodInfo handleAsync = interface_.GetMethod(nameof(IHandle.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); } diff --git a/dotnet/src/Microsoft.AutoGen/Core/HandlerInvoker.cs b/dotnet/src/Microsoft.AutoGen/Core/HandlerInvoker.cs index e60d5f6bf..740b2575c 100644 --- a/dotnet/src/Microsoft.AutoGen/Core/HandlerInvoker.cs +++ b/dotnet/src/Microsoft.AutoGen/Core/HandlerInvoker.cs @@ -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);