1
0
mirror of https://github.com/chylex/.NET-Community-Toolkit.git synced 2025-04-10 11:15:45 +02:00

Added optimized method lookup on NS2.1 and up

This commit is contained in:
Sergio Pedri 2021-03-22 23:31:28 +01:00
parent 33e081638b
commit b5db31a403

View File

@ -98,29 +98,45 @@ public static void RegisterAll<TToken>(this IMessenger messenger, object recipie
// target recipient type, and just create a delegate wrapping that method if it is found.
static Action<IMessenger, object, TToken> LoadRegistrationMethodsForType(Type recipientType)
{
if (recipientType.Assembly.GetType("Microsoft.Toolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions") is Type extensionsType &&
extensionsType.GetMethods(BindingFlags.Static | BindingFlags.Public) is MethodInfo[] { Length: > 0 } extensionMethods)
if (recipientType.Assembly.GetType("Microsoft.Toolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions") is Type extensionsType)
{
foreach (MethodInfo methodInfo in extensionMethods)
#if NETSTANDARD2_0
// .NET Standard 2.0 doesn't have Type.MakeGenericMethodParameter, so we need to iterate manually
foreach (MethodInfo methodInfo in extensionsType.GetMethods(BindingFlags.Static | BindingFlags.Public))
{
if (methodInfo.Name is "RegisterAll" &&
methodInfo.GetParameters()[1].ParameterType == recipientType)
{
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(typeof(TToken));
Type delegateType = typeof(Action<,,>).MakeGenericType(typeof(IMessenger), recipientType, typeof(TToken));
// We need an unsafe cast here like we did in StrongReferenceMessenger to be able to treat the new delegate
// type as if it was covariant in its input recipient. This allows us to keep the type-specific overloads in
// the generated code while still creating non-generic delegates here. This code is technically safe since
// we have control over what types we're working with, and we know the type conversions will always be valid.
return Unsafe.As<Action<IMessenger, object, TToken>>(genericMethodInfo.CreateDelegate(delegateType));
return CreateGenericDelegate(recipientType, methodInfo);
}
}
#else
// On .NET Standard 2.1 and up, we can directly look for the target method in one call
Type[] methodTypes = new[] { typeof(IMessenger), recipientType, Type.MakeGenericMethodParameter(0) };
if (extensionsType.GetMethod("RegisterAll", methodTypes) is MethodInfo methodInfo)
{
return CreateGenericDelegate(recipientType, methodInfo);
}
#endif
}
return LoadRegistrationMethodsForTypeFallback(recipientType);
}
// A shared method to create a generic delegate from an identified method
static Action<IMessenger, object, TToken> CreateGenericDelegate(Type recipientType, MethodInfo methodInfo)
{
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(typeof(TToken));
Type delegateType = typeof(Action<,,>).MakeGenericType(typeof(IMessenger), recipientType, typeof(TToken));
// We need an unsafe cast here like we did in StrongReferenceMessenger to be able to treat the new delegate
// type as if it was covariant in its input recipient. This allows us to keep the type-specific overloads in
// the generated code while still creating non-generic delegates here. This code is technically safe since
// we have control over what types we're working with, and we know the type conversions will always be valid.
return Unsafe.As<Action<IMessenger, object, TToken>>(genericMethodInfo.CreateDelegate(delegateType));
}
// Fallback method when a generated method is not found.
// This method is only invoked once per recipient type and token type, so we're not
// worried about making it super efficient, and we can use the LINQ code for clarity.