-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Look up Queryable operator MethodInfos without MakeGenericMethod #79717
Conversation
For NativeAOT compatibility, better speed. Closes dotnet#79199
Tagging subscribers to this area: @dotnet/area-system-linq Issue DetailsReplaces MethodInfo lookup for Queryable LINQ operators to stop using MakeGenericMethod, making them NativeAOT-compatible (and slightly faster). The current code caches the generic method definition and calls MakeGenericMethod every time: [RequiresDynamicCode("Calls System.Reflection.MethodInfo.MakeGenericMethod(params Type[])")]
public static MethodInfo Where_TSource_2(Type TSource) =>
(s_Where_TSource_2 ??= new Func<IQueryable<object>, Expression<Func<object, bool>>, IQueryable<object>>(Queryable.Where).GetMethodInfo().GetGenericMethodDefinition())
.MakeGenericMethod(TSource); This PR replaces that with the following: new Func<IQueryable<TSource>, Expression<Func<TSource, bool>>, IQueryable<TSource>>(Where).Method There's no more caching, but the new implementation is slightly faster than MakeGenericMethod:
Note the increase in allocations though. Benchmark codeBenchmarkRunner.Run<Benchmark>();
[MemoryDiagnoser]
public class Benchmark
{
private static readonly MethodInfo GenericMethodDefinition
= new Func<IQueryable<object>, Expression<Func<object, bool>>, IQueryable<object>>(Queryable.Where)
.GetMethodInfo().GetGenericMethodDefinition();
[Benchmark]
public MethodInfo ViaMethodGenericMethodValue()
=> GenericMethodDefinition.MakeGenericMethod(typeof(int));
[Benchmark]
public MethodInfo ViaMethodGenericMethodReference()
=> GenericMethodDefinition.MakeGenericMethod(typeof(string));
[Benchmark]
public MethodInfo ViaFuncValue()
=> new Func<IQueryable<int>, Expression<Func<int, bool>>, IQueryable<int>>(Queryable.Where).Method;
[Benchmark]
public MethodInfo ViaFuncReference()
=> new Func<IQueryable<string>, Expression<Func<string, bool>>, IQueryable<string>>(Queryable.Where).Method;
} Closes #79199 /cc @jkotas @vitek-karas @ajcvickers
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thank you!
Nice! Cc @jaredpar if there's an issue where we track use cases for a |
@MichalStrehovsky I don't believe there is an active issue around this. There was a lot of discussion around this around the time that This has come up several times in the following years though. The design is fairly well understood but there has never been the need to push it over the top. I think the way to move this forward is to outline the benefit this would have over the current solution (send it to me). I can add in the other scenarios I'm aware of and try to get an issue filed. |
Replaces MethodInfo lookup for Queryable LINQ operators to stop using MakeGenericMethod, making them NativeAOT-compatible (and slightly faster).
The current code caches the generic method definition and calls MakeGenericMethod every time:
This PR replaces that with the following:
There's no more caching, but the new implementation is slightly faster than MakeGenericMethod:
Note the increase in allocations though.
Benchmark code
Closes #79199
/cc @jkotas @vitek-karas @ajcvickers