diff --git a/src/EFCore/Query/QueryableMethods.cs b/src/EFCore/Query/QueryableMethods.cs index 96a0bcf81a5..1df5679098f 100644 --- a/src/EFCore/Query/QueryableMethods.cs +++ b/src/EFCore/Query/QueryableMethods.cs @@ -16,20 +16,11 @@ namespace Microsoft.EntityFrameworkCore.Query /// public static class QueryableMethods { - /// - /// The for - /// - public static MethodInfo AsQueryable { get; } + //public static MethodInfo AggregateWithoutSeed { get; } - /// - /// The for - /// - public static MethodInfo Cast { get; } + //public static MethodInfo AggregateWithSeedWithoutSelector { get; } - /// - /// The for - /// - public static MethodInfo OfType { get; } + //public static MethodInfo AggregateWithSeedSelector { get; } /// /// The for @@ -43,34 +34,33 @@ public static class QueryableMethods /// /// The for - /// + /// /// public static MethodInfo AnyWithPredicate { get; } - /// - /// The for - /// - public static MethodInfo Contains { get; } + //public static MethodInfo AsQueryableNonGeneric { get; } /// - /// The for + /// The for /// - public static MethodInfo Concat { get; } + public static MethodInfo AsQueryable { get; } /// - /// The for + /// The for /// - public static MethodInfo Except { get; } + public static MethodInfo Cast { get; } /// - /// The for + /// The for /// - public static MethodInfo Intersect { get; } + public static MethodInfo Concat { get; } /// - /// The for + /// The for /// - public static MethodInfo Union { get; } + public static MethodInfo Contains { get; } + + //public static MethodInfo ContainsWithComparer { get; } /// /// The for @@ -79,39 +69,26 @@ public static class QueryableMethods /// /// The for - /// + /// /// public static MethodInfo CountWithPredicate { get; } /// - /// The for - /// - public static MethodInfo LongCountWithoutPredicate { get; } - - /// - /// The for - /// - public static MethodInfo LongCountWithPredicate { get; } - - /// - /// The for + /// The for /// - public static MethodInfo MinWithSelector { get; } + public static MethodInfo DefaultIfEmptyWithoutArgument { get; } /// - /// The for + /// The for /// - public static MethodInfo MinWithoutSelector { get; } + public static MethodInfo DefaultIfEmptyWithArgument { get; } /// - /// The for + /// The for /// - public static MethodInfo MaxWithSelector { get; } + public static MethodInfo Distinct { get; } - /// - /// The for - /// - public static MethodInfo MaxWithoutSelector { get; } + //public static MethodInfo DistinctWithComparer { get; } /// /// The for @@ -123,6 +100,13 @@ public static class QueryableMethods /// public static MethodInfo ElementAtOrDefault { get; } + /// + /// The for + /// + public static MethodInfo Except { get; } + + //public static MethodInfo ExceptWithComparer { get; } + /// /// The for /// @@ -144,24 +128,63 @@ public static class QueryableMethods public static MethodInfo FirstOrDefaultWithPredicate { get; } /// - /// The for + /// The for /// - public static MethodInfo SingleWithoutPredicate { get; } + public static MethodInfo GroupByWithKeySelector { get; } /// - /// The for + /// The for + /// /// - public static MethodInfo SingleWithPredicate { get; } + public static MethodInfo GroupByWithKeyElementSelector { get; } + + //public static MethodInfo GroupByWithKeySelectorAndComparer { get; } + + //public static MethodInfo GroupByWithKeyElementSelectorAndComparer { get; } /// - /// The for + /// The for + /// /// - public static MethodInfo SingleOrDefaultWithoutPredicate { get; } + public static MethodInfo GroupByWithKeyElementResultSelector { get; } /// - /// The for + /// The for + /// /// - public static MethodInfo SingleOrDefaultWithPredicate { get; } + public static MethodInfo GroupByWithKeyResultSelector { get; } + + //public static MethodInfo GroupByWithKeyResultSelectorAndComparer { get; } + + //public static MethodInfo GroupByWithKeyElementResultSelectorAndComparer { get; } + + /// + /// The for + /// + /// + public static MethodInfo GroupJoin { get; } + + //public static MethodInfo GroupJoinWithComparer { get; } + + /// + /// The for + /// + public static MethodInfo Intersect { get; } + + //public static MethodInfo IntersectWithComparer { get; } + + /// + /// The for + /// + /// + public static MethodInfo Join { get; } + + //public static MethodInfo JoinWithComparer { get; } /// /// The for @@ -184,496 +207,642 @@ public static class QueryableMethods public static MethodInfo LastOrDefaultWithPredicate { get; } /// - /// The for - /// - public static MethodInfo Distinct { get; } - - /// - /// The for + /// The for /// - public static MethodInfo Reverse { get; } + public static MethodInfo LongCountWithoutPredicate { get; } /// - /// The for + /// The for /// - public static MethodInfo Where { get; } + public static MethodInfo LongCountWithPredicate { get; } /// - /// The for - /// + /// The for /// - public static MethodInfo Select { get; } + public static MethodInfo MaxWithoutSelector { get; } /// - /// The for + /// The for /// - public static MethodInfo Skip { get; } + public static MethodInfo MaxWithSelector { get; } /// - /// The for + /// The for /// - public static MethodInfo Take { get; } + public static MethodInfo MinWithoutSelector { get; } /// - /// The for + /// The for /// - public static MethodInfo SkipWhile { get; } + public static MethodInfo MinWithSelector { get; } /// - /// The for + /// The for /// - public static MethodInfo TakeWhile { get; } + public static MethodInfo OfType { get; } /// /// The for /// public static MethodInfo OrderBy { get; } + //public static MethodInfo OrderByWithComparer { get; } + /// /// The for /// /// public static MethodInfo OrderByDescending { get; } + //public static MethodInfo OrderByDescendingWithComparer { get; } + + /// + /// The for + /// + public static MethodInfo Reverse { get; } + /// /// The for - /// + /// /// - public static MethodInfo ThenBy { get; } + public static MethodInfo Select { get; } + + //public static MethodInfo SelectWithOrdinal { get; } /// /// The for - /// + /// /// - public static MethodInfo ThenByDescending { get; } + public static MethodInfo SelectManyWithoutCollectionSelector { get; } + + //public static MethodInfo SelectManyWithoutCollectionSelectorOrdinal { get; } /// - /// The for + /// The for + /// /// - public static MethodInfo DefaultIfEmptyWithoutArgument { get; } + public static MethodInfo SelectManyWithCollectionSelector { get; } + + //public static MethodInfo SelectManyWithCollectionSelectorOrdinal { get; } + + //public static MethodInfo SequenceEqual { get; } + + //public static MethodInfo SequenceEqualWithComparer { get; } /// - /// The for + /// The for /// - public static MethodInfo DefaultIfEmptyWithArgument { get; } + public static MethodInfo SingleWithoutPredicate { get; } /// - /// The for - /// + /// The for /// - public static MethodInfo Join { get; } + public static MethodInfo SingleWithPredicate { get; } /// - /// The for - /// + /// The for /// - public static MethodInfo GroupJoin { get; } + public static MethodInfo SingleOrDefaultWithoutPredicate { get; } /// - /// The for - /// + /// The for /// - public static MethodInfo SelectManyWithCollectionSelector { get; } + public static MethodInfo SingleOrDefaultWithPredicate { get; } /// - /// The for - /// + /// The for /// - public static MethodInfo SelectManyWithoutCollectionSelector { get; } + public static MethodInfo Skip { get; } /// - /// The for + /// The for /// - public static MethodInfo GroupByWithKeySelector { get; } + public static MethodInfo SkipWhile { get; } + + //public static MethodInfo SkipWhileOrdinal { get; } /// - /// The for - /// + /// The for /// - public static MethodInfo GroupByWithKeyElementSelector { get; } + public static MethodInfo Take { get; } + + /// + /// The for + /// + public static MethodInfo TakeWhile { get; } + + //public static MethodInfo TakeWhileOrdinal { get; } /// /// The for - /// + /// /// - public static MethodInfo GroupByWithKeyElementResultSelector { get; } + public static MethodInfo ThenBy { get; } + + //public static MethodInfo ThenByWithComparer { get; } /// /// The for - /// + /// /// - public static MethodInfo GroupByWithKeyResultSelector { get; } + public static MethodInfo ThenByDescending { get; } + + //public static MethodInfo ThenByDescendingWithComparer { get; } /// - /// Checks whether or not the given is one of the without a selector. + /// The for + /// + public static MethodInfo Union { get; } + + //public static MethodInfo UnionWithComparer { get; } + + /// + /// The for + /// + public static MethodInfo Where { get; } + + //public static MethodInfo WhereOrdinal { get; } + + //public static MethodInfo Zip { get; } + + /// + /// Checks whether or not the given is one of the without a selector. /// /// The method to check. /// if the method matches; otherwise. - public static bool IsSumWithoutSelector([NotNull] MethodInfo methodInfo) + public static bool IsAverageWithoutSelector([NotNull] MethodInfo methodInfo) { Check.NotNull(methodInfo, nameof(methodInfo)); - return SumWithoutSelectorMethods.Values.Contains(methodInfo); + return AverageWithoutSelectorMethods.Values.Contains(methodInfo); } /// - /// Checks whether or not the given is one of the with a selector. + /// Checks whether or not the given is one of the with a selector. /// /// The method to check. /// if the method matches; otherwise. - public static bool IsSumWithSelector([NotNull] MethodInfo methodInfo) + public static bool IsAverageWithSelector([NotNull] MethodInfo methodInfo) { Check.NotNull(methodInfo, nameof(methodInfo)); return methodInfo.IsGenericMethod - && SumWithSelectorMethods.Values.Contains(methodInfo.GetGenericMethodDefinition()); + && AverageWithSelectorMethods.Values.Contains(methodInfo.GetGenericMethodDefinition()); } /// - /// Checks whether or not the given is one of the without a selector. + /// Checks whether or not the given is one of the without a selector. /// /// The method to check. /// if the method matches; otherwise. - public static bool IsAverageWithoutSelector([NotNull] MethodInfo methodInfo) + public static bool IsSumWithoutSelector([NotNull] MethodInfo methodInfo) { Check.NotNull(methodInfo, nameof(methodInfo)); - return AverageWithoutSelectorMethods.Values.Contains(methodInfo); + return SumWithoutSelectorMethods.Values.Contains(methodInfo); } /// - /// Checks whether or not the given is one of the with a selector. + /// Checks whether or not the given is one of the with a selector. /// /// The method to check. /// if the method matches; otherwise. - public static bool IsAverageWithSelector([NotNull] MethodInfo methodInfo) + public static bool IsSumWithSelector([NotNull] MethodInfo methodInfo) { Check.NotNull(methodInfo, nameof(methodInfo)); return methodInfo.IsGenericMethod - && AverageWithSelectorMethods.Values.Contains(methodInfo.GetGenericMethodDefinition()); + && SumWithSelectorMethods.Values.Contains(methodInfo.GetGenericMethodDefinition()); } /// - /// Returns the for the method without a selector for the given type. + /// Returns the for the method without a selector for the given type. /// /// The generic type of the method to create. /// The . - public static MethodInfo GetSumWithoutSelector([NotNull] Type type) + public static MethodInfo GetAverageWithoutSelector([NotNull] Type type) { Check.NotNull(type, nameof(type)); - return SumWithoutSelectorMethods[type]; + return AverageWithoutSelectorMethods[type]; } /// - /// Returns the for the method with a selector for the given type. + /// Returns the for the method with a selector for the given type. /// /// The generic type of the method to create. /// The . - public static MethodInfo GetSumWithSelector([NotNull] Type type) + public static MethodInfo GetAverageWithSelector([NotNull] Type type) { Check.NotNull(type, nameof(type)); - return SumWithSelectorMethods[type]; + return AverageWithSelectorMethods[type]; } /// - /// Returns the for the method without a selector for the given type. + /// Returns the for the method without a selector for the given type. /// /// The generic type of the method to create. /// The . - public static MethodInfo GetAverageWithoutSelector([NotNull] Type type) + public static MethodInfo GetSumWithoutSelector([NotNull] Type type) { Check.NotNull(type, nameof(type)); - return AverageWithoutSelectorMethods[type]; + return SumWithoutSelectorMethods[type]; } /// - /// Returns the for the method with a selector for the given type. + /// Returns the for the method with a selector for the given type. /// /// The generic type of the method to create. /// The . - public static MethodInfo GetAverageWithSelector([NotNull] Type type) + public static MethodInfo GetSumWithSelector([NotNull] Type type) { Check.NotNull(type, nameof(type)); - return AverageWithSelectorMethods[type]; + return SumWithSelectorMethods[type]; } - private static Dictionary SumWithoutSelectorMethods { get; } - private static Dictionary SumWithSelectorMethods { get; } private static Dictionary AverageWithoutSelectorMethods { get; } private static Dictionary AverageWithSelectorMethods { get; } + private static Dictionary SumWithoutSelectorMethods { get; } + private static Dictionary SumWithSelectorMethods { get; } static QueryableMethods() { - var queryableMethods = typeof(Queryable) - .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly).ToList(); - - AsQueryable = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.AsQueryable) && mi.IsGenericMethod && mi.GetParameters().Length == 1); - Cast = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Cast) && mi.GetParameters().Length == 1); - OfType = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.OfType) && mi.GetParameters().Length == 1); - - All = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.All) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - AnyWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Any) && mi.GetParameters().Length == 1); - AnyWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Any) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - Contains = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Contains) && mi.GetParameters().Length == 2); - - Concat = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Concat) && mi.GetParameters().Length == 2); - Except = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Except) && mi.GetParameters().Length == 2); - Intersect = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Intersect) && mi.GetParameters().Length == 2); - Union = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Union) && mi.GetParameters().Length == 2); - - CountWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Count) && mi.GetParameters().Length == 1); - CountWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Count) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - LongCountWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.LongCount) && mi.GetParameters().Length == 1); - LongCountWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.LongCount) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - MinWithSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Min) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - MinWithoutSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Min) && mi.GetParameters().Length == 1); - MaxWithSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Max) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - MaxWithoutSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Max) && mi.GetParameters().Length == 1); - - ElementAt = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.ElementAt) && mi.GetParameters().Length == 2); - ElementAtOrDefault = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.ElementAtOrDefault) && mi.GetParameters().Length == 2); - FirstWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.First) && mi.GetParameters().Length == 1); - FirstWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.First) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - FirstOrDefaultWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.FirstOrDefault) && mi.GetParameters().Length == 1); - FirstOrDefaultWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.FirstOrDefault) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - SingleWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Single) && mi.GetParameters().Length == 1); - SingleWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Single) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - SingleOrDefaultWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.SingleOrDefault) && mi.GetParameters().Length == 1); - SingleOrDefaultWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.SingleOrDefault) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - LastWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Last) && mi.GetParameters().Length == 1); - LastWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Last) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - LastOrDefaultWithoutPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.LastOrDefault) && mi.GetParameters().Length == 1); - LastOrDefaultWithPredicate = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.LastOrDefault) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - - Distinct = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Distinct) && mi.GetParameters().Length == 1); - Reverse = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Reverse) && mi.GetParameters().Length == 1); - Where = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Where) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - Select = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Select) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - Skip = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Skip) && mi.GetParameters().Length == 2); - Take = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Take) && mi.GetParameters().Length == 2); - SkipWhile = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.SkipWhile) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - TakeWhile = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.TakeWhile) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - OrderBy = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.OrderBy) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - OrderByDescending = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.OrderByDescending) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - ThenBy = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.ThenBy) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - ThenByDescending = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.ThenByDescending) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - DefaultIfEmptyWithoutArgument = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.DefaultIfEmpty) && mi.GetParameters().Length == 1); - DefaultIfEmptyWithArgument = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.DefaultIfEmpty) && mi.GetParameters().Length == 2); - - Join = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.Join) && mi.GetParameters().Length == 5); - GroupJoin = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.GroupJoin) && mi.GetParameters().Length == 5); - SelectManyWithCollectionSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.SelectMany) - && mi.GetParameters().Length == 3 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - SelectManyWithoutCollectionSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.SelectMany) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - - GroupByWithKeySelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.GroupBy) - && mi.GetParameters().Length == 2 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType)); - GroupByWithKeyElementSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.GroupBy) - && mi.GetParameters().Length == 3 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType) - && IsExpressionOfFunc(mi.GetParameters()[2].ParameterType)); - GroupByWithKeyElementResultSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.GroupBy) - && mi.GetParameters().Length == 4 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType) - && IsExpressionOfFunc(mi.GetParameters()[2].ParameterType) - && IsExpressionOfFunc( - mi.GetParameters()[3].ParameterType, 3)); - GroupByWithKeyResultSelector = queryableMethods.Single( - mi => mi.Name == nameof(Queryable.GroupBy) - && mi.GetParameters().Length == 3 - && IsExpressionOfFunc(mi.GetParameters()[1].ParameterType) - && IsExpressionOfFunc( - mi.GetParameters()[2].ParameterType, 3)); - - SumWithoutSelectorMethods = new Dictionary + var queryableMethodGroups = typeof(Queryable) + .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly) + .GroupBy(mi => mi.Name) + .ToDictionary(e => e.Key, l => l.ToList()); + + All = GetMethod(nameof(Queryable.All), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + AnyWithoutPredicate = GetMethod(nameof(Queryable.Any), 1, + types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + AnyWithPredicate = GetMethod(nameof(Queryable.Any), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + AsQueryable = GetMethod(nameof(Queryable.AsQueryable), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + Cast = GetMethod(nameof(Queryable.Cast), 1, types => new[] { typeof(IQueryable) }); + + Concat = GetMethod(nameof(Queryable.Concat), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + Contains = GetMethod(nameof(Queryable.Contains), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + types[0] + }); + + CountWithoutPredicate = GetMethod(nameof(Queryable.Count), 1, + types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + CountWithPredicate = GetMethod(nameof(Queryable.Count), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + DefaultIfEmptyWithoutArgument = GetMethod(nameof(Queryable.DefaultIfEmpty), 1, + types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + DefaultIfEmptyWithArgument = GetMethod(nameof(Queryable.DefaultIfEmpty), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + types[0] + }); + + Distinct = GetMethod(nameof(Queryable.Distinct), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + ElementAt = GetMethod(nameof(Queryable.ElementAt), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(int) + }); + + ElementAtOrDefault = GetMethod(nameof(Queryable.ElementAtOrDefault), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(int) + }); + + Except = GetMethod(nameof(Queryable.Except), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + FirstWithoutPredicate = GetMethod(nameof(Queryable.First), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + FirstWithPredicate = GetMethod(nameof(Queryable.First), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + FirstOrDefaultWithoutPredicate = GetMethod(nameof(Queryable.FirstOrDefault), 1, + types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + FirstOrDefaultWithPredicate = GetMethod(nameof(Queryable.FirstOrDefault), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + GroupByWithKeySelector = GetMethod(nameof(Queryable.GroupBy), 2, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])) + }); + + GroupByWithKeyElementSelector = GetMethod(nameof(Queryable.GroupBy), 3, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[2])) + }); + + GroupByWithKeyElementResultSelector = GetMethod(nameof(Queryable.GroupBy), 4, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[2])), + typeof(Expression<>).MakeGenericType(typeof(Func<,,>).MakeGenericType( + types[1], typeof(IEnumerable<>).MakeGenericType(types[2]), types[3])) + }); + + GroupByWithKeyResultSelector = GetMethod(nameof(Queryable.GroupBy), 3, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])), + typeof(Expression<>).MakeGenericType(typeof(Func<,,>).MakeGenericType( + types[1], typeof(IEnumerable<>).MakeGenericType(types[0]), types[2])) + }); + + GroupJoin = GetMethod(nameof(Queryable.GroupJoin), 4, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[1]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[2])), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[1], types[2])), + typeof(Expression<>).MakeGenericType(typeof(Func<,,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1]), types[3])) + }); + + Intersect = GetMethod(nameof(Queryable.Intersect), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + Join = GetMethod(nameof(Queryable.Join), 4, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[1]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[2])), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[1], types[2])), + typeof(Expression<>).MakeGenericType(typeof(Func<,,>).MakeGenericType(types[0], types[1], types[3])) + }); + + LastWithoutPredicate = GetMethod(nameof(Queryable.Last), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + LastWithPredicate = GetMethod(nameof(Queryable.Last), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + LastOrDefaultWithoutPredicate = GetMethod(nameof(Queryable.LastOrDefault), 1, + types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + LastOrDefaultWithPredicate = GetMethod(nameof(Queryable.LastOrDefault), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + LongCountWithoutPredicate = GetMethod(nameof(Queryable.LongCount), 1, + types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + LongCountWithPredicate = GetMethod(nameof(Queryable.LongCount), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + MaxWithoutSelector = GetMethod(nameof(Queryable.Max), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + MaxWithSelector = GetMethod(nameof(Queryable.Max), 2, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])) + }); + + MinWithoutSelector = GetMethod(nameof(Queryable.Min), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + MinWithSelector = GetMethod(nameof(Queryable.Min), 2, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])) + }); + + OfType = GetMethod(nameof(Queryable.OfType), 1, types => new[] { typeof(IQueryable) }); + + OrderBy = GetMethod(nameof(Queryable.OrderBy), 2, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])) + }); + + OrderByDescending = GetMethod(nameof(Queryable.OrderByDescending), 2, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])) + }); + + Reverse = GetMethod(nameof(Queryable.Reverse), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + Select = GetMethod(nameof(Queryable.Select), 2, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])) + }); + + SelectManyWithoutCollectionSelector = GetMethod(nameof(Queryable.SelectMany), 2, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1]))) + }); + + SelectManyWithCollectionSelector = GetMethod(nameof(Queryable.SelectMany), 3, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1]))), + typeof(Expression<>).MakeGenericType(typeof(Func<,,>).MakeGenericType(types[0], types[1], types[2])) + }); + + SingleWithoutPredicate = GetMethod(nameof(Queryable.Single), 1, types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + SingleWithPredicate = GetMethod(nameof(Queryable.Single), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + SingleOrDefaultWithoutPredicate = GetMethod(nameof(Queryable.SingleOrDefault), 1, + types => new[] { typeof(IQueryable<>).MakeGenericType(types[0]) }); + + SingleOrDefaultWithPredicate = GetMethod(nameof(Queryable.SingleOrDefault), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + Skip = GetMethod(nameof(Queryable.Skip), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(int) + }); + + SkipWhile = GetMethod(nameof(Queryable.SkipWhile), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + Take = GetMethod(nameof(Queryable.Take), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(int) + }); + + TakeWhile = GetMethod(nameof(Queryable.TakeWhile), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + ThenBy = GetMethod(nameof(Queryable.ThenBy), 2, + types => new[] + { + typeof(IOrderedQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])) + }); + + ThenByDescending = GetMethod(nameof(Queryable.ThenByDescending), 2, + types => new[] + { + typeof(IOrderedQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[1])) + }); + + Union = GetMethod(nameof(Queryable.Union), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + Where = GetMethod(nameof(Queryable.Where), 1, + types => new[] + { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool))) + }); + + var numericTypes = new[] { - { typeof(decimal), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(long), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(int), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(double), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(float), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(decimal?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(long?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(int?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(double?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(float?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Sum)) } + typeof(int), + typeof(int?), + typeof(long), + typeof(long?), + typeof(float), + typeof(float?), + typeof(double), + typeof(double?), + typeof(decimal), + typeof(decimal?) }; - SumWithSelectorMethods = new Dictionary - { - { typeof(decimal), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(long), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(int), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(double), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(float), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(decimal?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(long?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(int?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(double?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) }, - { typeof(float?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Sum)) } - }; + AverageWithoutSelectorMethods = new Dictionary(); + AverageWithSelectorMethods = new Dictionary(); + SumWithoutSelectorMethods = new Dictionary(); + SumWithSelectorMethods = new Dictionary(); - AverageWithoutSelectorMethods = new Dictionary + foreach (var type in numericTypes) { - { typeof(decimal), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(long), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(int), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(double), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(float), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(decimal?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(long?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(int?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(double?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(float?), GetSumOrAverageWithoutSelector(queryableMethods, nameof(Queryable.Average)) } - }; - - AverageWithSelectorMethods = new Dictionary - { - { typeof(decimal), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(long), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(int), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(double), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(float), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(decimal?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(long?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(int?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(double?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) }, - { typeof(float?), GetSumOrAverageWithSelector(queryableMethods, nameof(Queryable.Average)) } - }; - - static MethodInfo GetSumOrAverageWithoutSelector(List queryableMethods, string methodName) - => queryableMethods.Single( - mi => mi.Name == methodName - && mi.GetParameters().Length == 1 - && mi.GetParameters()[0].ParameterType.GetGenericArguments()[0] == typeof(T)); - - static MethodInfo GetSumOrAverageWithSelector(List queryableMethods, string methodName) - => queryableMethods.Single( - mi => mi.Name == methodName - && mi.GetParameters().Length == 2 - && IsSelector(mi.GetParameters()[1].ParameterType)); - - static bool IsExpressionOfFunc(Type type, int funcGenericArgs = 2) - => type.IsGenericType - && type.GetGenericTypeDefinition() == typeof(Expression<>) - && type.GetGenericArguments()[0].IsGenericType - && type.GetGenericArguments()[0].GetGenericArguments().Length == funcGenericArgs; - - static bool IsSelector(Type type) - => type.IsGenericType - && type.GetGenericTypeDefinition() == typeof(Expression<>) - && type.GetGenericArguments()[0].IsGenericType - && type.GetGenericArguments()[0].GetGenericArguments().Length == 2 - && type.GetGenericArguments()[0].GetGenericArguments()[1] == typeof(T); + AverageWithoutSelectorMethods[type] = GetMethod( + nameof(Queryable.Average), 0, types => new[] { typeof(IQueryable<>).MakeGenericType(type) }); + AverageWithSelectorMethods[type] = GetMethod( + nameof(Queryable.Average), 1, types => new[] { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], type)) + }); + SumWithoutSelectorMethods[type] = GetMethod( + nameof(Queryable.Sum), 0, types => new[] { typeof(IQueryable<>).MakeGenericType(type) }); + SumWithSelectorMethods[type] = GetMethod( + nameof(Queryable.Sum), 1, types => new[] { + typeof(IQueryable<>).MakeGenericType(types[0]), + typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], type)) + }); + } + + MethodInfo GetMethod(string name, int genericParameterCount, Func parameterGenerator) + => queryableMethodGroups[name].Single( + mi => ((genericParameterCount == 0 && !mi.IsGenericMethod) + || (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount)) + && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( + parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : Array.Empty()))); } } -} +} \ No newline at end of file diff --git a/src/Shared/EnumerableMethods.cs b/src/Shared/EnumerableMethods.cs index 3fe8c76250f..06e316dbe52 100644 --- a/src/Shared/EnumerableMethods.cs +++ b/src/Shared/EnumerableMethods.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -10,73 +11,196 @@ namespace Microsoft.EntityFrameworkCore { internal static class EnumerableMethods { - public static MethodInfo AsEnumerable { get; } - public static MethodInfo Cast { get; } - public static MethodInfo OfType { get; } + //public static MethodInfo AggregateWithoutSeed { get; } + + //public static MethodInfo AggregateWithSeedWithoutSelector { get; } + + //public static MethodInfo AggregateWithSeedSelector { get; } public static MethodInfo All { get; } + public static MethodInfo AnyWithoutPredicate { get; } + public static MethodInfo AnyWithPredicate { get; } - public static MethodInfo Contains { get; } - public static MethodInfo SequenceEqual { get; } - public static MethodInfo ToList { get; } - public static MethodInfo ToArray { get; } + //public static Append { get; } + + public static MethodInfo AsEnumerable { get; } + + public static MethodInfo Cast { get; } public static MethodInfo Concat { get; } - public static MethodInfo Except { get; } - public static MethodInfo Intersect { get; } - public static MethodInfo Union { get; } + + public static MethodInfo Contains { get; } + + //public static MethodInfo ContainsWithComparer { get; } public static MethodInfo CountWithoutPredicate { get; } + public static MethodInfo CountWithPredicate { get; } - public static MethodInfo LongCountWithoutPredicate { get; } - public static MethodInfo LongCountWithPredicate { get; } - public static MethodInfo MinWithSelector { get; } - public static MethodInfo MinWithoutSelector { get; } - public static MethodInfo MaxWithSelector { get; } - public static MethodInfo MaxWithoutSelector { get; } + + public static MethodInfo DefaultIfEmptyWithoutArgument { get; } + + public static MethodInfo DefaultIfEmptyWithArgument { get; } + + public static MethodInfo Distinct { get; } + + //public static MethodInfo DistinctWithComparer { get; } public static MethodInfo ElementAt { get; } + public static MethodInfo ElementAtOrDefault { get; } + + //public static MethodInfo Empty { get; } + + public static MethodInfo Except { get; } + + //public static MethodInfo ExceptWithComparer { get; } + public static MethodInfo FirstWithoutPredicate { get; } + public static MethodInfo FirstWithPredicate { get; } + public static MethodInfo FirstOrDefaultWithoutPredicate { get; } + public static MethodInfo FirstOrDefaultWithPredicate { get; } - public static MethodInfo SingleWithoutPredicate { get; } - public static MethodInfo SingleWithPredicate { get; } - public static MethodInfo SingleOrDefaultWithoutPredicate { get; } - public static MethodInfo SingleOrDefaultWithPredicate { get; } + + public static MethodInfo GroupByWithKeySelector { get; } + + public static MethodInfo GroupByWithKeyElementSelector { get; } + + //public static MethodInfo GroupByWithKeySelectorAndComparer { get; } + + //public static MethodInfo GroupByWithKeyElementSelectorAndComparer { get; } + + public static MethodInfo GroupByWithKeyElementResultSelector { get; } + + public static MethodInfo GroupByWithKeyResultSelector { get; } + + //public static MethodInfo GroupByWithKeyResultSelectorAndComparer { get; } + + //public static MethodInfo GroupByWithKeyElementResultSelectorAndComparer { get; } + + public static MethodInfo GroupJoin { get; } + + //public static MethodInfo GroupJoinWithComparer { get; } + + public static MethodInfo Intersect { get; } + + //public static MethodInfo IntersectWithComparer { get; } + + public static MethodInfo Join { get; } + + //public static MethodInfo JoinWithComparer { get; } + public static MethodInfo LastWithoutPredicate { get; } + public static MethodInfo LastWithPredicate { get; } + public static MethodInfo LastOrDefaultWithoutPredicate { get; } + public static MethodInfo LastOrDefaultWithPredicate { get; } - public static MethodInfo Distinct { get; } + public static MethodInfo LongCountWithoutPredicate { get; } + + public static MethodInfo LongCountWithPredicate { get; } + + public static MethodInfo MaxWithoutSelector { get; } + + public static MethodInfo MaxWithSelector { get; } + + public static MethodInfo MinWithoutSelector { get; } + + public static MethodInfo MinWithSelector { get; } + + public static MethodInfo OfType { get; } + + public static MethodInfo OrderBy { get; } + + //public static MethodInfo OrderByWithComparer { get; } + + public static MethodInfo OrderByDescending { get; } + + //public static MethodInfo OrderByDescendingWithComparer { get; } + + //public static MethodInfo Prepend { get; } + + //public static MethodInfo Range { get; } + + //public static MethodInfo Repeat { get; } + public static MethodInfo Reverse { get; } - public static MethodInfo Where { get; } + public static MethodInfo Select { get; } + public static MethodInfo SelectWithOrdinal { get; } + + public static MethodInfo SelectManyWithoutCollectionSelector { get; } + + //public static MethodInfo SelectManyWithoutCollectionSelectorOrdinal { get; } + + public static MethodInfo SelectManyWithCollectionSelector { get; } + + //public static MethodInfo SelectManyWithCollectionSelectorOrdinal { get; } + + public static MethodInfo SequenceEqual { get; } + + //public static MethodInfo SequenceEqualWithComparer { get; } + + public static MethodInfo SingleWithoutPredicate { get; } + + public static MethodInfo SingleWithPredicate { get; } + + public static MethodInfo SingleOrDefaultWithoutPredicate { get; } + + public static MethodInfo SingleOrDefaultWithPredicate { get; } + public static MethodInfo Skip { get; } - public static MethodInfo Take { get; } + public static MethodInfo SkipWhile { get; } + + //public static MethodInfo SkipWhileOrdinal { get; } + + public static MethodInfo Take { get; } + public static MethodInfo TakeWhile { get; } - public static MethodInfo OrderBy { get; } - public static MethodInfo OrderByDescending { get; } + + //public static MethodInfo TakeWhileOrdinal { get; } + public static MethodInfo ThenBy { get; } + + //public static MethodInfo ThenByWithComparer { get; } + public static MethodInfo ThenByDescending { get; } - public static MethodInfo DefaultIfEmptyWithoutArgument { get; } - public static MethodInfo DefaultIfEmptyWithArgument { get; } - public static MethodInfo Join { get; } - public static MethodInfo GroupJoin { get; } - public static MethodInfo SelectManyWithCollectionSelector { get; } - public static MethodInfo SelectManyWithoutCollectionSelector { get; } + //public static MethodInfo ThenByDescendingWithComparer { get; } - public static MethodInfo GroupByWithKeySelector { get; } - public static MethodInfo GroupByWithKeyElementSelector { get; } - public static MethodInfo GroupByWithKeyElementResultSelector { get; } - public static MethodInfo GroupByWithKeyResultSelector { get; } + public static MethodInfo ToArray { get; } + + //public static MethodInfo ToDictionaryWithKeySelector { get; } + //public static MethodInfo ToDictionaryWithKeySelectorAndComparer { get; } + //public static MethodInfo ToDictionaryWithKeyElementSelector { get; } + //public static MethodInfo ToDictionaryWithKeyElementSelectorAndComparer { get; } + + //public static MethodInfo ToHashSet { get; } + //public static MethodInfo ToHashSetWithComparer { get; } + + public static MethodInfo ToList { get; } + + //public static MethodInfo ToLookupWithKeySelector { get; } + //public static MethodInfo ToLookupWithKeySelectorAndComparer { get; } + //public static MethodInfo ToLookupWithKeyElementSelector { get; } + //public static MethodInfo ToLookupWithKeyElementSelectorAndComparer { get; } + + public static MethodInfo Union { get; } + + //public static MethodInfo UnionWithComparer { get; } + + public static MethodInfo Where { get; } + + //public static MethodInfo WhereOrdinal { get; } + + //public static MethodInfo Zip { get; } private static Dictionary SumWithoutSelectorMethods { get; } private static Dictionary SumWithSelectorMethods { get; } @@ -135,337 +259,414 @@ public static MethodInfo GetMinWithSelector(Type type) static EnumerableMethods() { - var enumerableMethods = typeof(Enumerable) + var queryableMethodGroups = typeof(Enumerable) .GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly) - .ToList(); - - AsEnumerable = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.AsEnumerable) && mi.IsGenericMethod && mi.GetParameters().Length == 1); - Cast = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Cast) && mi.GetParameters().Length == 1); - OfType = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.OfType) && mi.GetParameters().Length == 1); - - All = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.All) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - AnyWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Any) && mi.GetParameters().Length == 1); - AnyWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Any) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - Contains = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Contains) && mi.GetParameters().Length == 2); - SequenceEqual = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.SequenceEqual) && mi.GetParameters().Length == 2); - - ToList = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.ToList) && mi.GetParameters().Length == 1); - ToArray = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.ToArray) && mi.GetParameters().Length == 1); - - Concat = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Concat) && mi.GetParameters().Length == 2); - Except = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Except) && mi.GetParameters().Length == 2); - Intersect = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Intersect) && mi.GetParameters().Length == 2); - Union = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Union) && mi.GetParameters().Length == 2); - - CountWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Count) && mi.GetParameters().Length == 1); - CountWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Count) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - LongCountWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.LongCount) && mi.GetParameters().Length == 1); - LongCountWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.LongCount) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - MinWithSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Min) - && mi.GetParameters().Length == 2 - && mi.GetGenericArguments().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - MinWithoutSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Min) - && mi.GetParameters().Length == 1 - && mi.IsGenericMethodDefinition); - MaxWithSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Max) - && mi.GetParameters().Length == 2 - && mi.GetGenericArguments().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - MaxWithoutSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Max) - && mi.GetParameters().Length == 1 - && mi.IsGenericMethodDefinition); - - ElementAt = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.ElementAt) && mi.GetParameters().Length == 2); - ElementAtOrDefault = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.ElementAtOrDefault) && mi.GetParameters().Length == 2); - FirstWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.First) && mi.GetParameters().Length == 1); - FirstWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.First) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - FirstOrDefaultWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.FirstOrDefault) && mi.GetParameters().Length == 1); - FirstOrDefaultWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.FirstOrDefault) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - SingleWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Single) && mi.GetParameters().Length == 1); - SingleWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Single) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - SingleOrDefaultWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.SingleOrDefault) && mi.GetParameters().Length == 1); - SingleOrDefaultWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.SingleOrDefault) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - LastWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Last) && mi.GetParameters().Length == 1); - LastWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Last) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - LastOrDefaultWithoutPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.LastOrDefault) && mi.GetParameters().Length == 1); - LastOrDefaultWithPredicate = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.LastOrDefault) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - - Distinct = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Distinct) && mi.GetParameters().Length == 1); - Reverse = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Reverse) && mi.GetParameters().Length == 1); - Where = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Where) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - Select = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Select) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - SelectWithOrdinal = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Select) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType, funcGenericArgs: 3)); - Skip = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Skip) && mi.GetParameters().Length == 2); - Take = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Take) && mi.GetParameters().Length == 2); - SkipWhile = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.SkipWhile) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - TakeWhile = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.TakeWhile) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - OrderBy = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.OrderBy) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - OrderByDescending = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.OrderByDescending) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - ThenBy = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.ThenBy) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - ThenByDescending = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.ThenByDescending) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - DefaultIfEmptyWithoutArgument = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.DefaultIfEmpty) && mi.GetParameters().Length == 1); - DefaultIfEmptyWithArgument = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.DefaultIfEmpty) && mi.GetParameters().Length == 2); - - Join = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.Join) && mi.GetParameters().Length == 5); - GroupJoin = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.GroupJoin) && mi.GetParameters().Length == 5); - SelectManyWithCollectionSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.SelectMany) - && mi.GetParameters().Length == 3 - && IsFunc(mi.GetParameters()[1].ParameterType)); - SelectManyWithoutCollectionSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.SelectMany) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - - GroupByWithKeySelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.GroupBy) - && mi.GetParameters().Length == 2 - && IsFunc(mi.GetParameters()[1].ParameterType)); - GroupByWithKeyElementSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.GroupBy) - && mi.GetParameters().Length == 3 - && IsFunc(mi.GetParameters()[1].ParameterType) - && IsFunc(mi.GetParameters()[2].ParameterType)); - GroupByWithKeyElementResultSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.GroupBy) - && mi.GetParameters().Length == 4 - && IsFunc(mi.GetParameters()[1].ParameterType) - && IsFunc(mi.GetParameters()[2].ParameterType) - && IsFunc( - mi.GetParameters()[3].ParameterType, 3)); - GroupByWithKeyResultSelector = enumerableMethods.Single( - mi => mi.Name == nameof(Enumerable.GroupBy) - && mi.GetParameters().Length == 3 - && IsFunc(mi.GetParameters()[1].ParameterType) - && IsFunc( - mi.GetParameters()[2].ParameterType, 3)); - - SumWithoutSelectorMethods = new Dictionary + .GroupBy(mi => mi.Name) + .ToDictionary(e => e.Key, l => l.ToList()); + + All = GetMethod(nameof(Enumerable.All), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + AnyWithoutPredicate = GetMethod(nameof(Enumerable.Any), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + AnyWithPredicate = GetMethod(nameof(Enumerable.Any), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + AsEnumerable = GetMethod(nameof(Enumerable.AsEnumerable), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + Cast = GetMethod(nameof(Enumerable.Cast), 1, types => new[] { typeof(IEnumerable) }); + + Concat = GetMethod(nameof(Enumerable.Concat), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + Contains = GetMethod(nameof(Enumerable.Contains), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + types[0] + }); + + CountWithoutPredicate = GetMethod(nameof(Enumerable.Count), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + CountWithPredicate = GetMethod(nameof(Enumerable.Count), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + DefaultIfEmptyWithoutArgument = GetMethod(nameof(Enumerable.DefaultIfEmpty), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + DefaultIfEmptyWithArgument = GetMethod(nameof(Enumerable.DefaultIfEmpty), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + types[0] + }); + + Distinct = GetMethod(nameof(Enumerable.Distinct), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + ElementAt = GetMethod(nameof(Enumerable.ElementAt), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(int) + }); + + ElementAtOrDefault = GetMethod(nameof(Enumerable.ElementAtOrDefault), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(int) + }); + + Except = GetMethod(nameof(Enumerable.Except), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + FirstWithoutPredicate = GetMethod(nameof(Enumerable.First), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + FirstWithPredicate = GetMethod(nameof(Enumerable.First), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + FirstOrDefaultWithoutPredicate = GetMethod(nameof(Enumerable.FirstOrDefault), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + FirstOrDefaultWithPredicate = GetMethod(nameof(Enumerable.FirstOrDefault), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + GroupByWithKeySelector = GetMethod(nameof(Enumerable.GroupBy), 2, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]) + }); + + GroupByWithKeyElementSelector = GetMethod(nameof(Enumerable.GroupBy), 3, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]), + typeof(Func<,>).MakeGenericType(types[0], types[2]) + }); + + GroupByWithKeyElementResultSelector = GetMethod(nameof(Enumerable.GroupBy), 4, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]), + typeof(Func<,>).MakeGenericType(types[0], types[2]), + typeof(Func<,,>).MakeGenericType( + types[1], typeof(IEnumerable<>).MakeGenericType(types[2]), types[3]) + }); + + GroupByWithKeyResultSelector = GetMethod(nameof(Enumerable.GroupBy), 3, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]), + typeof(Func<,,>).MakeGenericType( + types[1], typeof(IEnumerable<>).MakeGenericType(types[0]), types[2]) + }); + + GroupJoin = GetMethod(nameof(Enumerable.GroupJoin), 4, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[1]), + typeof(Func<,>).MakeGenericType(types[0], types[2]), + typeof(Func<,>).MakeGenericType(types[1], types[2]), + typeof(Func<,,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1]), types[3]) + }); + + Intersect = GetMethod(nameof(Enumerable.Intersect), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + Join = GetMethod(nameof(Enumerable.Join), 4, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[1]), + typeof(Func<,>).MakeGenericType(types[0], types[2]), + typeof(Func<,>).MakeGenericType(types[1], types[2]), + typeof(Func<,,>).MakeGenericType(types[0], types[1], types[3]) + }); + + LastWithoutPredicate = GetMethod(nameof(Enumerable.Last), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + LastWithPredicate = GetMethod(nameof(Enumerable.Last), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + LastOrDefaultWithoutPredicate = GetMethod(nameof(Enumerable.LastOrDefault), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + LastOrDefaultWithPredicate = GetMethod(nameof(Enumerable.LastOrDefault), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + LongCountWithoutPredicate = GetMethod(nameof(Enumerable.LongCount), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + LongCountWithPredicate = GetMethod(nameof(Enumerable.LongCount), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + MaxWithoutSelector = GetMethod(nameof(Enumerable.Max), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + MaxWithSelector = GetMethod(nameof(Enumerable.Max), 2, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]) + }); + + MinWithoutSelector = GetMethod(nameof(Enumerable.Min), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + MinWithSelector = GetMethod(nameof(Enumerable.Min), 2, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]) + }); + + OfType = GetMethod(nameof(Enumerable.OfType), 1, types => new[] { typeof(IEnumerable) }); + + OrderBy = GetMethod(nameof(Enumerable.OrderBy), 2, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]) + }); + + OrderByDescending = GetMethod(nameof(Enumerable.OrderByDescending), 2, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]) + }); + + Reverse = GetMethod(nameof(Enumerable.Reverse), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + Select = GetMethod(nameof(Enumerable.Select), 2, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]) + }); + + SelectWithOrdinal = GetMethod(nameof(Enumerable.Select), 2, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,,>).MakeGenericType(types[0], typeof(int), types[1]) + }); + + SelectManyWithoutCollectionSelector = GetMethod(nameof(Enumerable.SelectMany), 2, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1])) + }); + + SelectManyWithCollectionSelector = GetMethod(nameof(Enumerable.SelectMany), 3, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1])), + typeof(Func<,,>).MakeGenericType(types[0], types[1], types[2]) + }); + + SequenceEqual = GetMethod(nameof(Enumerable.SequenceEqual), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + SingleWithoutPredicate = GetMethod(nameof(Enumerable.Single), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + SingleWithPredicate = GetMethod(nameof(Enumerable.Single), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + SingleOrDefaultWithoutPredicate = GetMethod(nameof(Enumerable.SingleOrDefault), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + SingleOrDefaultWithPredicate = GetMethod(nameof(Enumerable.SingleOrDefault), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + Skip = GetMethod(nameof(Enumerable.Skip), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(int) + }); + + SkipWhile = GetMethod(nameof(Enumerable.SkipWhile), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + ToArray = GetMethod(nameof(Enumerable.ToArray), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + ToList = GetMethod(nameof(Enumerable.ToList), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); + + Take = GetMethod(nameof(Enumerable.Take), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(int) + }); + + TakeWhile = GetMethod(nameof(Enumerable.TakeWhile), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + ThenBy = GetMethod(nameof(Enumerable.ThenBy), 2, + types => new[] + { + typeof(IOrderedEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]) + }); + + ThenByDescending = GetMethod(nameof(Enumerable.ThenByDescending), 2, + types => new[] + { + typeof(IOrderedEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]) + }); + + Union = GetMethod(nameof(Enumerable.Union), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[0]) + }); + + Where = GetMethod(nameof(Enumerable.Where), 1, + types => new[] + { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) + }); + + var numericTypes = new[] { - { typeof(decimal), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(long), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(int), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(double), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(float), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(decimal?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(long?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(int?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(double?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(float?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Sum)) } + typeof(int), + typeof(int?), + typeof(long), + typeof(long?), + typeof(float), + typeof(float?), + typeof(double), + typeof(double?), + typeof(decimal), + typeof(decimal?) }; - SumWithSelectorMethods = new Dictionary - { - { typeof(decimal), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(long), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(int), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(double), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(float), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(decimal?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(long?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(int?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(double?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) }, - { typeof(float?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Sum)) } - }; + AverageWithoutSelectorMethods = new Dictionary(); + AverageWithSelectorMethods = new Dictionary(); + MaxWithoutSelectorMethods = new Dictionary(); + MaxWithSelectorMethods = new Dictionary(); + MinWithoutSelectorMethods = new Dictionary(); + MinWithSelectorMethods = new Dictionary(); + SumWithoutSelectorMethods = new Dictionary(); + SumWithSelectorMethods = new Dictionary(); - AverageWithoutSelectorMethods = new Dictionary + foreach (var type in numericTypes) { - { typeof(decimal), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(long), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(int), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(double), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(float), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(decimal?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(long?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(int?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(double?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(float?), GetMethodWithoutSelector(enumerableMethods, nameof(Enumerable.Average)) } - }; - - AverageWithSelectorMethods = new Dictionary - { - { typeof(decimal), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(long), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(int), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(double), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(float), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(decimal?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(long?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(int?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(double?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) }, - { typeof(float?), GetMethodWithSelector(enumerableMethods, nameof(Enumerable.Average)) } - }; - - MaxWithoutSelectorMethods = new Dictionary - { - { typeof(decimal), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(long), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(int), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(double), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(float), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(decimal?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(long?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(int?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(double?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(float?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Max)) } - }; - - MaxWithSelectorMethods = new Dictionary - { - { typeof(decimal), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(long), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(int), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(double), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(float), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(decimal?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(long?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(int?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(double?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) }, - { typeof(float?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Max)) } - }; - - MinWithoutSelectorMethods = new Dictionary - { - { typeof(decimal), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(long), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(int), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(double), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(float), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(decimal?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(long?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(int?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(double?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(float?), GetMethodWithoutSelector(enumerableMethods, nameof(Queryable.Min)) } - }; - - MinWithSelectorMethods = new Dictionary - { - { typeof(decimal), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(long), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(int), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(double), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(float), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(decimal?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(long?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(int?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(double?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) }, - { typeof(float?), GetMethodWithSelector(enumerableMethods, nameof(Queryable.Min)) } - }; - - static MethodInfo GetMethodWithoutSelector(List enumerableMethods, string methodName) - => enumerableMethods.Single( - mi => mi.Name == methodName - && mi.GetParameters().Length == 1 - && mi.GetParameters()[0].ParameterType.GetGenericArguments()[0] == typeof(T)); - - static MethodInfo GetMethodWithSelector(List enumerableMethods, string methodName) - => enumerableMethods.Single( - mi => mi.Name == methodName - && mi.GetParameters().Length == 2 - && IsSelector(mi.GetParameters()[1].ParameterType)); - - static bool IsFunc(Type type, int funcGenericArgs = 2) - => type.IsGenericType - && (funcGenericArgs == 1 && type.GetGenericTypeDefinition() == typeof(Func<>) - || funcGenericArgs == 2 && type.GetGenericTypeDefinition() == typeof(Func<,>) - || funcGenericArgs == 3 && type.GetGenericTypeDefinition() == typeof(Func<,,>)); - - static bool IsSelector(Type type) - => type.IsGenericType - && type.GetGenericTypeDefinition() == typeof(Func<,>) - && type.GetGenericArguments()[1] == typeof(T); + AverageWithoutSelectorMethods[type] = GetMethod( + nameof(Enumerable.Average), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); + AverageWithSelectorMethods[type] = GetMethod( + nameof(Enumerable.Average), 1, types => new[] { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], type) + }); + MaxWithoutSelectorMethods[type] = GetMethod( + nameof(Enumerable.Max), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); + MaxWithSelectorMethods[type] = GetMethod( + nameof(Enumerable.Max), 1, types => new[] { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], type) + }); + MinWithoutSelectorMethods[type] = GetMethod( + nameof(Enumerable.Min), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); + MinWithSelectorMethods[type] = GetMethod( + nameof(Enumerable.Min), 1, types => new[] { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], type) + }); + SumWithoutSelectorMethods[type] = GetMethod( + nameof(Enumerable.Sum), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); + SumWithSelectorMethods[type] = GetMethod( + nameof(Enumerable.Sum), 1, types => new[] { + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], type) + }); + } + + MethodInfo GetMethod(string name, int genericParameterCount, Func parameterGenerator) + => queryableMethodGroups[name].Single( + mi => ((genericParameterCount == 0 && !mi.IsGenericMethod) + || (mi.IsGenericMethod && mi.GetGenericArguments().Length == genericParameterCount)) + && mi.GetParameters().Select(e => e.ParameterType).SequenceEqual( + parameterGenerator(mi.IsGenericMethod ? mi.GetGenericArguments() : Array.Empty()))); } } -} +} \ No newline at end of file