dotnet / dotnet/linker

Support basic MethodInfo caching pattern with MakeGenericMethod (and MakeGenericType)

Open
#2,482 11 comments 2 reactions 0 assignees View on GitHub
area-Linker: DataFlow
Dominant language
C#
Stars
392
Forks
128
Avg merge
2d 10h
Merged PRs (30d)
2

Description

Following #2480, the linker identifies uses of MakeGenericMethod/Type where the type is statically. However, in order for the code to be understandable to the linker, it must perform reflection each time as follows:

```c#
var method = typeof(Program).GetMethod("Foo").MakeGenericMethod(typeof(Bar));
method.Invoke(null, null);
```

However, it's common to perform the reflection lookup once, and store the result in a static readonly variable. This is important for proper factoring where the same generic method is used frequently (e.g. EF Core), and can maybe also impact perf (through repeated calls to GetMethod):

```c#
private static readonly MethodInfo FooMethod = typeof(Program).GetMethod("Foo");

...

var method = FooMethod.MakeGenericMethod(typeof(Bar));
method.Invoke(null, null);
```

When doing this, DynamicallyAccessedMembers on FooMethod aren't taken into account, and the program fails at runtime (see full sample below). It would be helpful if the linker identified basic caching patterns such as the above to make this work.

Full code sample

```c#
class Program
{
private static readonly MethodInfo FooMethod = typeof(Program).GetMethod("Foo");

public static void Main()
=> Go(typeof(Program));

public static void Go(Type type)
{
// Doesn't work - makes sense:
// var method = type.GetMethod("Foo").MakeGenericMethod(typeof(Bar));
// method.Invoke(null, null);

// Works:
// var method = typeof(Program).GetMethod("Foo").MakeGenericMethod(typeof(Bar));
// method.Invoke(null, null);

// Doesn't work - making this work is the issue ask:
// var method = FooMethod.MakeGenericMethod(typeof(Bar));
// method.Invoke(null, null);

// Also works:
// Foo();
}

public static T Foo<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
{
Console.WriteLine("in Foo");
return Activator.CreateInstance();
}

class Bar
{
public void SomeMethod()
=> Console.WriteLine("In Bar.SomeMethod");
}
}
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.