diff --git a/src/NHibernate.Test/NHSpecificTest/NH3952/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH3952/Entity.cs new file mode 100644 index 00000000000..caf5e80cdd4 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3952/Entity.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.NH3952 +{ + class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual Guid? ParentId { get; set; } + public virtual ISet Children { get; set; } + public virtual string[] Hobbies { get; set; } + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs new file mode 100644 index 00000000000..dea02b22cd0 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH3952 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using (ISession session = OpenSession()) + using (ITransaction transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + + var e2 = new Entity { Name = "Sally", ParentId = e1.Id, Hobbies = new[] { "Inline skate", "Sailing" } }; + session.Save(e2); + + var e3 = new Entity { Name = "Max", ParentId = e1.Id }; + session.Save(e3); + + session.Flush(); + transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (ISession session = OpenSession()) + using (ITransaction transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + + session.Flush(); + transaction.Commit(); + } + } + + [Test] + public void SimpleNestedSelect() + { + using (ISession session = OpenSession()) + using (session.BeginTransaction()) + { + var result = session.Query() + .Select(e => new { e.Name, children = e.Children.Select(c => c.Name).ToArray() }) + .OrderBy(e => e.Name) + .ToList(); + + Assert.AreEqual(3, result.Count); + Assert.AreEqual(2, result[0].children.Length); + Assert.AreEqual("Bob", result[0].Name); + Assert.Contains("Max", result[0].children); + Assert.Contains("Sally", result[0].children); + Assert.AreEqual(0, result[1].children.Length + result[2].children.Length); + } + } + + [Test] + public void ArraySelect() + { + using (ISession session = OpenSession()) + using (session.BeginTransaction()) + { + var result = session.Query() + .Select(e => new { e.Name, e.Hobbies }) + .OrderBy(e => e.Name) + .ToList(); + + Assert.AreEqual(3, result.Count); + Assert.AreEqual(2, result[2].Hobbies.Length); + Assert.AreEqual("Sally", result[2].Name); + Assert.Contains("Inline skate", result[2].Hobbies); + Assert.Contains("Sailing", result[2].Hobbies); + Assert.AreEqual(0, result[0].Hobbies.Length + result[1].Hobbies.Length); + } + } + + private static readonly MethodInfo CastMethodDefinition = ReflectionHelper.GetMethodDefinition( + () => Enumerable.Cast(null)); + + private static readonly MethodInfo CastMethod = ReflectionHelper.GetMethod( + () => Enumerable.Cast(null)); + + [Test, Explicit("Just a blunt perf comparison among some reflection patterns used in NH")] + public void ReflectionBluntPerfCompare() + { + var swCached = new Stopwatch(); + swCached.Start(); + for (var i = 0; i < 1000; i++) + { + Trace.TraceInformation(CastMethod.ToString()); + } + swCached.Stop(); + + var swCachedDef = new Stopwatch(); + swCachedDef.Start(); + for (var i = 0; i < 1000; i++) + { + var cast = CastMethodDefinition.MakeGenericMethod(new[] { typeof(int) }); + Trace.TraceInformation(cast.ToString()); + } + swCachedDef.Stop(); + + var swRefl2 = new Stopwatch(); + swRefl2.Start(); + for (var i = 0; i < 1000; i++) + { + var cast = GetMethod2(Enumerable.Cast, (IEnumerable)null); + Trace.TraceInformation(cast.ToString()); + } + swRefl2.Stop(); + + var swRefl2Def = new Stopwatch(); + swRefl2Def.Start(); + for (var i = 0; i < 1000; i++) + { + var cast = GetMethodDefinition2(Enumerable.Cast, (IEnumerable)null) + .MakeGenericMethod(new[] { typeof(int) }); + Trace.TraceInformation(cast.ToString()); + } + swRefl2Def.Stop(); + + var swRefl = new Stopwatch(); + swRefl.Start(); + for (var i = 0; i < 1000; i++) + { + var cast = ReflectionHelper.GetMethod(() => Enumerable.Cast(null)); + Trace.TraceInformation(cast.ToString()); + } + swRefl.Stop(); + + var swReflDef = new Stopwatch(); + swReflDef.Start(); + for (var i = 0; i < 1000; i++) + { + var cast = ReflectionHelper.GetMethodDefinition(() => Enumerable.Cast(null)) + .MakeGenericMethod(new[] { typeof(int) }); + Trace.TraceInformation(cast.ToString()); + } + swReflDef.Stop(); + + var swEnHlp = new Stopwatch(); + swEnHlp.Start(); + for (var i = 0; i < 1000; i++) + { + // Testing the obsolete helper perf. Disable obsolete warning. Remove this swEnHlp part of the test if this helper is to be removed. +#pragma warning disable 0618 + var cast = EnumerableHelper.GetMethod("Cast", new[] { typeof(IEnumerable) }, new[] { typeof(int) }); +#pragma warning restore 0618 + Trace.TraceInformation(cast.ToString()); + } + swEnHlp.Stop(); + + Assert.Pass(@"Blunt perf timings: +Cached method: {0} +Cached method definition + make gen: {1} +Hazzik GetMethod: {5} +Hazzik GetMethodDefinition + make gen: {6} +ReflectionHelper.GetMethod: {2} +ReflectionHelper.GetMethodDefinition + make gen: {3} +EnumerableHelper.GetMethod(generic overload): {4}", + swCached.Elapsed, swCachedDef.Elapsed, swRefl.Elapsed, swReflDef.Elapsed, swEnHlp.Elapsed, + swRefl2.Elapsed, swRefl2Def.Elapsed); + } + + public static MethodInfo GetMethod2(Func func, T arg1) + { + return func.Method; + } + + public static MethodInfo GetMethodDefinition2(Func func, T arg1) + { + var method = GetMethod2(func, arg1); + return method.IsGenericMethod ? method.GetGenericMethodDefinition() : method; + } + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3952/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH3952/Mappings.hbm.xml new file mode 100644 index 00000000000..6f23678f327 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3952/Mappings.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index f21597364cf..3b64847ed1b 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -736,6 +736,8 @@ + + @@ -3201,6 +3203,7 @@ + diff --git a/src/NHibernate/Linq/EnumerableHelper.cs b/src/NHibernate/Linq/EnumerableHelper.cs index 405c6fb2c99..f36bf432506 100644 --- a/src/NHibernate/Linq/EnumerableHelper.cs +++ b/src/NHibernate/Linq/EnumerableHelper.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -57,7 +56,7 @@ public static MethodInfo GetMethod(Expression method) if (method == null) throw new ArgumentNullException("method"); - return ((MethodCallExpression) method.Body).Method; + return ((MethodCallExpression)method.Body).Method; } /// @@ -93,8 +92,8 @@ internal static System.Type GetPropertyOrFieldType(this MemberInfo memberInfo) return null; } } - - // TODO rename / remove - reflection helper above is better + + [Obsolete("Please use ReflectionHelper instead")] public static class EnumerableHelper { public static MethodInfo GetMethod(string name, System.Type[] parameterTypes) diff --git a/src/NHibernate/Linq/NestedSelects/NestedSelectRewriter.cs b/src/NHibernate/Linq/NestedSelects/NestedSelectRewriter.cs index 4358d7b2cae..56a5ded7921 100644 --- a/src/NHibernate/Linq/NestedSelects/NestedSelectRewriter.cs +++ b/src/NHibernate/Linq/NestedSelects/NestedSelectRewriter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; @@ -16,7 +15,12 @@ namespace NHibernate.Linq.NestedSelects { static class NestedSelectRewriter { - private static readonly MethodInfo CastMethod = EnumerableHelper.GetMethod("Cast", new[] { typeof (IEnumerable) }, new[] { typeof (object[]) }); + private static readonly MethodInfo CastMethod = + ReflectionHelper.GetMethod(() => Enumerable.Cast(null)); + private static readonly MethodInfo GroupByMethod = ReflectionHelper.GetMethod( + () => Enumerable.GroupBy(null, null, (Func)null)); + private static readonly MethodInfo WhereMethod = ReflectionHelper.GetMethod( + () => Enumerable.Where(null, (Func)null)); public static void ReWrite(QueryModel queryModel, ISessionFactory sessionFactory) { @@ -51,15 +55,11 @@ public static void ReWrite(QueryModel queryModel, ISessionFactory sessionFactory var keySelector = CreateSelector(elementExpression, 0); var elementSelector = CreateSelector(elementExpression, 1); - - var groupBy = EnumerableHelper.GetMethod("GroupBy", - new[] { typeof (IEnumerable<>), typeof (Func<,>), typeof (Func<,>) }, - new[] { typeof (object[]), typeof (Tuple), typeof (Tuple) }); - + var input = Expression.Parameter(typeof (IEnumerable), "input"); var lambda = Expression.Lambda( - Expression.Call(groupBy, + Expression.Call(GroupByMethod, Expression.Call(CastMethod, input), keySelector, elementSelector), @@ -154,24 +154,16 @@ private static LambdaExpression MakeSelector(ICollection eleme private static Expression SubCollectionQuery(System.Type collectionType, System.Type elementType, Expression source, Expression predicate, Expression selector) { // source.Where(predicate).Select(selector).ToList(); - var whereMethod = EnumerableHelper.GetMethod("Where", - new[] { typeof (IEnumerable<>), typeof (Func<,>) }, - new[] { typeof (Tuple) }); - - var selectMethod = EnumerableHelper.GetMethod("Select", - new[] { typeof (IEnumerable<>), typeof (Func<,>) }, - new[] { typeof (Tuple), elementType }); + var selectMethod = ReflectionCache.EnumerableMethods.SelectDefinition.MakeGenericMethod(new[] { typeof(Tuple), elementType }); var select = Expression.Call(selectMethod, - Expression.Call(whereMethod, source, predicate), + Expression.Call(WhereMethod, source, predicate), selector); if (collectionType.IsArray) { - var toArrayMethod = EnumerableHelper.GetMethod("ToArray", - new[] { typeof(IEnumerable<>) }, - new[] { elementType }); + var toArrayMethod = ReflectionCache.EnumerableMethods.ToArrayDefinition.MakeGenericMethod(new[] { elementType }); var array = Expression.Call(toArrayMethod, @select); return array; @@ -181,9 +173,7 @@ private static Expression SubCollectionQuery(System.Type collectionType, System. if (constructor != null) return Expression.New(constructor, (Expression) @select); - var toListMethod = EnumerableHelper.GetMethod("ToList", - new[] { typeof (IEnumerable<>) }, - new[] { elementType }); + var toListMethod = ReflectionCache.EnumerableMethods.ToListDefinition.MakeGenericMethod(new[] { elementType }); return Expression.Call(Expression.Call(toListMethod, @select), "AsReadonly", diff --git a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessAggregate.cs b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessAggregate.cs index c4cc369afa8..2a7f9f81995 100644 --- a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessAggregate.cs +++ b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessAggregate.cs @@ -1,17 +1,16 @@ -using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Linq.Expressions; +using NHibernate.Util; using Remotion.Linq.Clauses.ResultOperators; using Remotion.Linq.Clauses.StreamedData; using Remotion.Linq.Parsing.ExpressionTreeVisitors; namespace NHibernate.Linq.Visitors.ResultOperatorProcessors { - public class ProcessAggregate : IResultOperatorProcessor - { - public void Process(AggregateResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree) - { + public class ProcessAggregate : IResultOperatorProcessor + { + public void Process(AggregateResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree) + { var inputExpr = ((StreamedSequenceInfo)queryModelVisitor.PreviousEvaluationType).ItemExpression; var inputType = inputExpr.Type; var paramExpr = Expression.Parameter(inputType, "item"); @@ -22,11 +21,10 @@ public void Process(AggregateResultOperator resultOperator, QueryModelVisitor qu var inputList = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(typeof(object)), "inputList"); - var castToItem = EnumerableHelper.GetMethod("Cast", new[] { typeof(IEnumerable) }, new[] { inputType }); + var castToItem = ReflectionCache.EnumerableMethods.CastDefinition.MakeGenericMethod(new[] { inputType }); var castToItemExpr = Expression.Call(castToItem, inputList); - var aggregate = ReflectionHelper.GetMethodDefinition(() => Enumerable.Aggregate(null, null)); - aggregate = aggregate.GetGenericMethodDefinition().MakeGenericMethod(inputType); + var aggregate = ReflectionCache.EnumerableMethods.AggregateDefinition.MakeGenericMethod(inputType); MethodCallExpression call = Expression.Call( aggregate, @@ -36,5 +34,5 @@ public void Process(AggregateResultOperator resultOperator, QueryModelVisitor qu tree.AddListTransformer(Expression.Lambda(call, inputList)); } - } + } } \ No newline at end of file diff --git a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessAggregateFromSeed.cs b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessAggregateFromSeed.cs index e3dd5fc7a0c..34f3b4d39fe 100644 --- a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessAggregateFromSeed.cs +++ b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessAggregateFromSeed.cs @@ -1,40 +1,36 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Linq.Expressions; -using System.Text; -using Remotion.Linq.Clauses.ExpressionTreeVisitors; +using NHibernate.Util; using Remotion.Linq.Clauses.ResultOperators; using Remotion.Linq.Clauses.StreamedData; using Remotion.Linq.Parsing.ExpressionTreeVisitors; namespace NHibernate.Linq.Visitors.ResultOperatorProcessors { - public class ProcessAggregateFromSeed : IResultOperatorProcessor - { - public void Process(AggregateFromSeedResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree) - { - var inputExpr = ((StreamedSequenceInfo) queryModelVisitor.PreviousEvaluationType).ItemExpression; + public class ProcessAggregateFromSeed : IResultOperatorProcessor + { + public void Process(AggregateFromSeedResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree) + { + var inputExpr = ((StreamedSequenceInfo)queryModelVisitor.PreviousEvaluationType).ItemExpression; var inputType = inputExpr.Type; - var paramExpr = Expression.Parameter(inputType, "item"); - var accumulatorFunc = Expression.Lambda( + var paramExpr = Expression.Parameter(inputType, "item"); + var accumulatorFunc = Expression.Lambda( ReplacingExpressionTreeVisitor.Replace(inputExpr, paramExpr, resultOperator.Func.Body), resultOperator.Func.Parameters[0], paramExpr); - + var accumulatorType = resultOperator.Func.Parameters[0].Type; var inputList = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(typeof(object)), "inputList"); - var castToItem = EnumerableHelper.GetMethod("Cast", new[] { typeof(IEnumerable) }, new[] { inputType }); + var castToItem = ReflectionCache.EnumerableMethods.CastDefinition.MakeGenericMethod(new[] { inputType }); var castToItemExpr = Expression.Call(castToItem, inputList); MethodCallExpression call; if (resultOperator.OptionalResultSelector == null) { - var aggregate = ReflectionHelper.GetMethodDefinition(() => Enumerable.Aggregate(null, null, null)); - aggregate = aggregate.GetGenericMethodDefinition().MakeGenericMethod(inputType, accumulatorType); + var aggregate = ReflectionCache.EnumerableMethods.AggregateWithSeedDefinition + .MakeGenericMethod(inputType, accumulatorType); call = Expression.Call( aggregate, @@ -46,8 +42,8 @@ public void Process(AggregateFromSeedResultOperator resultOperator, QueryModelVi else { var selectorType = resultOperator.OptionalResultSelector.Type.GetGenericArguments()[2]; - var aggregate = ReflectionHelper.GetMethodDefinition(() => Enumerable.Aggregate(null, null, null, null)); - aggregate = aggregate.GetGenericMethodDefinition().MakeGenericMethod(inputType, accumulatorType, selectorType); + var aggregate = ReflectionCache.EnumerableMethods.AggregateWithSeedAndResultSelectorDefinition + .MakeGenericMethod(inputType, accumulatorType, selectorType); call = Expression.Call( aggregate, @@ -60,5 +56,5 @@ public void Process(AggregateFromSeedResultOperator resultOperator, QueryModelVi tree.AddListTransformer(Expression.Lambda(call, inputList)); } - } + } } diff --git a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessClientSideSelect.cs b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessClientSideSelect.cs index 44dbacc577a..81bf0fc1c7d 100644 --- a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessClientSideSelect.cs +++ b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessClientSideSelect.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq.Expressions; using NHibernate.Linq.GroupBy; +using NHibernate.Util; namespace NHibernate.Linq.Visitors.ResultOperatorProcessors { @@ -14,8 +14,8 @@ public void Process(ClientSideSelect resultOperator, QueryModelVisitor queryMode var inputList = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(inputType), "inputList"); - var selectMethod = EnumerableHelper.GetMethod("Select", new[] { typeof(IEnumerable<>), typeof(Func<,>) }, new[] { inputType, outputType }); - var toListMethod = EnumerableHelper.GetMethod("ToList", new[] { typeof(IEnumerable<>) }, new[] { outputType }); + var selectMethod = ReflectionCache.EnumerableMethods.SelectDefinition.MakeGenericMethod(new[] { inputType, outputType }); + var toListMethod = ReflectionCache.EnumerableMethods.ToListDefinition.MakeGenericMethod(new[] { outputType }); var lambda = Expression.Lambda( Expression.Call(toListMethod, diff --git a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessNonAggregatingGroupBy.cs b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessNonAggregatingGroupBy.cs index cd21dc08d30..abaf20e1471 100644 --- a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessNonAggregatingGroupBy.cs +++ b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessNonAggregatingGroupBy.cs @@ -1,8 +1,8 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq.Expressions; using NHibernate.Linq.ResultOperators; +using NHibernate.Util; using Remotion.Linq.Clauses.ExpressionTreeVisitors; namespace NHibernate.Linq.Visitors.ResultOperatorProcessors @@ -26,13 +26,12 @@ public void Process(NonAggregatingGroupBy resultOperator, QueryModelVisitor quer var elementSelectorExpr = ReverseResolvingExpressionTreeVisitor.ReverseResolve(selector, elementSelector); - var groupByMethod = EnumerableHelper.GetMethod("GroupBy", - new[] { typeof(IEnumerable<>), typeof(Func<,>), typeof(Func<,>) }, - new[] { sourceType, keyType, elementType }); + var groupByMethod = ReflectionCache.EnumerableMethods.GroupByWithElementSelectorDefinition + .MakeGenericMethod(new[] { sourceType, keyType, elementType }); - var castToItem = EnumerableHelper.GetMethod("Cast", new[] { typeof(IEnumerable) }, new[] { sourceType }); + var castToItem = ReflectionCache.EnumerableMethods.CastDefinition.MakeGenericMethod(new[] { sourceType }); - var toList = EnumerableHelper.GetMethod("ToList", new[] { typeof(IEnumerable<>) }, new[] { resultOperator.GroupBy.ItemType }); + var toList = ReflectionCache.EnumerableMethods.ToListDefinition.MakeGenericMethod(new[] { resultOperator.GroupBy.ItemType }); Expression castToItemExpr = Expression.Call(castToItem, listParameter); diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 851c1a7fc6d..d850d9107da 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -740,6 +740,7 @@ + diff --git a/src/NHibernate/Util/ReflectionCache.cs b/src/NHibernate/Util/ReflectionCache.cs new file mode 100644 index 00000000000..8cd4a94253c --- /dev/null +++ b/src/NHibernate/Util/ReflectionCache.cs @@ -0,0 +1,44 @@ +using System; +using System.Linq; +using System.Reflection; +using NHibernate.Linq; + +namespace NHibernate.Util +{ + internal static class ReflectionCache + { + // When adding a method to this cache, please follow the naming convention of those subclasses and fields: + // - Add your method to a subclass named according to the type holding the method, and suffixed with "Methods". + // - Name the field according to the method name. + // - If the method has overloads, suffix it with "With" followed by its parameter names. Do not list parameters + // common to all overloads. + // - If the method is a generic method definition, add "Definition" as final suffix. + // - If the method is generic, suffix it with "On" followed by its generic parameter type names. + // Avoid caching here narrow cases, such as those using specific types and unlikely to be used by many classes. + // Cache them instead in classes using them. + internal static class EnumerableMethods + { + internal static readonly MethodInfo AggregateDefinition = + ReflectionHelper.GetMethodDefinition(() => Enumerable.Aggregate(null, null)); + internal static readonly MethodInfo AggregateWithSeedDefinition = + ReflectionHelper.GetMethodDefinition(() => Enumerable.Aggregate(null, null, null)); + internal static readonly MethodInfo AggregateWithSeedAndResultSelectorDefinition = + ReflectionHelper.GetMethodDefinition(() => Enumerable.Aggregate(null, null, null, null)); + + internal static readonly MethodInfo CastDefinition = + ReflectionHelper.GetMethodDefinition(() => Enumerable.Cast(null)); + + internal static readonly MethodInfo GroupByWithElementSelectorDefinition = ReflectionHelper.GetMethodDefinition( + () => Enumerable.GroupBy(null, null, (Func)null)); + + internal static readonly MethodInfo SelectDefinition = + ReflectionHelper.GetMethodDefinition(() => Enumerable.Select(null, (Func)null)); + + internal static readonly MethodInfo ToArrayDefinition = + ReflectionHelper.GetMethodDefinition(() => Enumerable.ToArray(null)); + + internal static readonly MethodInfo ToListDefinition = + ReflectionHelper.GetMethodDefinition(() => Enumerable.ToList(null)); + } + } +} \ No newline at end of file