-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background and Motivation
Trying to invoke a method on a generic Type through reflection is not easy. The caller needs to find the method on the instantiated type in order to invoke it. Typically finding the method is done through type.GetMethod("foo")
, which doesn't have a great performance characteristic.
Making such code trim-compatible is even harder because the ILLinker doesn't know exactly which method you are trying to find, since the Type is dynamic.
For example, trying to dynamically get the Result
of a Task<TResult>
object today is done with the following code:
Lines 345 to 354 in 7b90eac
object? result; | |
Type task_type = task.GetType(); | |
if (task_type == typeof(Task)) | |
{ | |
result = System.Array.Empty<object>(); | |
} | |
else | |
{ | |
result = task_type.GetMethod("get_Result")?.Invoke(task, System.Array.Empty<object>()); | |
} |
Instead, we should have a method on Type
that returns the invokable MethodInfo given the MethodInfo on the generic type definition.
Proposed API
namespace System
{
public class Type
{
+ /// <summary>
+ /// Searches for the constructed generic member that matches the specified generic member definition.
+ /// </summary>
+ /// <param name="member">
+ /// The <see cref="MemberInfo"/> representing the generic definition of the member.
+ /// </param>
+ /// <returns>An object representing the member on the current constructed generic type that matches the specified generic definition, if found; otherwise, null.</returns>
+ public virtual MemberInfo? GetMemberFromGenericMemberDefinition(MemberInfo member);
}
}
Note: The proposed name matches the existing API on MemberInfo bool HasSameMetadataDefinitionAs(MemberInfo other)
Usage Examples
The above example of getting the Result
of a Task<TResult>
object would then look like the following, which would be trim-compatible.
class Runtime
{
private static readonly MethodInfo s_getResultMethodInfo = typeof(Task<>).GetMethod("get_Result");
public void Complete(Task task)
{
object? result;
Type task_type = task.GetType();
if (task_type == typeof(Task))
{
result = System.Array.Empty<object>();
}
else
{
result = task_type.GetMemberWithSameMetadataDefinition(s_getResultMethodInfo)?.Invoke(task, System.Array.Empty<object>());
}
}
}
See #45727 (comment) for the original suggestion for this API.