@@ -35,8 +35,9 @@ public static bool Any([NotNull] this IQueryable source)
35
35
{
36
36
Check . NotNull ( source , nameof ( source ) ) ;
37
37
38
- return Queryable . Any ( ( IQueryable < object > ) source ) ;
38
+ return Execute < bool > ( _any , source ) ;
39
39
}
40
+ private static readonly MethodInfo _any = GetMethod ( nameof ( Queryable . Any ) ) ;
40
41
41
42
/// <summary>
42
43
/// Determines whether a sequence contains any elements.
@@ -61,15 +62,9 @@ public static bool Any([NotNull] this IQueryable source, [NotNull] string predic
61
62
bool createParameterCtor = source . IsLinqToObjects ( ) ;
62
63
LambdaExpression lambda = DynamicExpression . ParseLambda ( createParameterCtor , source . ElementType , null , predicate , args ) ;
63
64
64
- return source . Provider . Execute < bool > (
65
- Expression . Call (
66
- typeof ( Queryable ) , "Any" ,
67
- new [ ] { source . ElementType } ,
68
- source . Expression ,
69
- Expression . Quote ( lambda )
70
- )
71
- ) ;
65
+ return Execute < bool > ( _anyPredicate , source , Expression . Quote ( lambda ) ) ;
72
66
}
67
+ private static readonly MethodInfo _anyPredicate = GetMethod ( nameof ( Queryable . Any ) , 1 ) ;
73
68
#endregion Any
74
69
75
70
#region AsEnumerable
@@ -112,8 +107,9 @@ public static int Count([NotNull] this IQueryable source)
112
107
{
113
108
Check . NotNull ( source , nameof ( source ) ) ;
114
109
115
- return Queryable . Count ( ( IQueryable < object > ) source ) ;
110
+ return Execute < int > ( _count , source ) ;
116
111
}
112
+ private static readonly MethodInfo _count = GetMethod ( nameof ( Queryable . Count ) ) ;
117
113
118
114
/// <summary>
119
115
/// Returns the number of elements in a sequence.
@@ -136,17 +132,11 @@ public static int Count([NotNull] this IQueryable source, [NotNull] string predi
136
132
Check . NotEmpty ( predicate , nameof ( predicate ) ) ;
137
133
138
134
bool createParameterCtor = source . IsLinqToObjects ( ) ;
139
- LambdaExpression lambda = DynamicExpression . ParseLambda ( createParameterCtor , source . ElementType , typeof ( bool ) , predicate , args ) ;
135
+ LambdaExpression lambda = DynamicExpression . ParseLambda ( createParameterCtor , source . ElementType , null , predicate , args ) ;
140
136
141
- return source . Provider . Execute < int > (
142
- Expression . Call (
143
- typeof ( Queryable ) , "Count" ,
144
- new [ ] { source . ElementType } ,
145
- source . Expression ,
146
- Expression . Quote ( lambda )
147
- )
148
- ) ;
137
+ return Execute < int > ( _countPredicate , source , Expression . Quote ( lambda ) ) ;
149
138
}
139
+ private static readonly MethodInfo _countPredicate = GetMethod ( nameof ( Queryable . Count ) , 1 ) ;
150
140
#endregion Count
151
141
152
142
#region Distinct
@@ -174,7 +164,7 @@ public static IQueryable Distinct([NotNull] this IQueryable source)
174
164
}
175
165
#endregion Distinct
176
166
177
- #region First/FirstOrDefault
167
+ #region First
178
168
/// <summary>
179
169
/// Returns the first element of a sequence.
180
170
/// </summary>
@@ -188,16 +178,40 @@ public static dynamic First([NotNull] this IQueryable source)
188
178
{
189
179
Check . NotNull ( source , nameof ( source ) ) ;
190
180
191
- return source . Provider . Execute ( Expression . Call (
192
- typeof ( Queryable ) , "First" ,
193
- new [ ] { source . ElementType } , source . Expression ) ) ;
181
+ return Execute ( _first , source ) ;
182
+ }
183
+ private static readonly MethodInfo _first = GetMethod ( nameof ( Queryable . First ) ) ;
184
+
185
+ /// <summary>
186
+ /// Returns the first element of a sequence that satisfies a specified condition.
187
+ /// </summary>
188
+ /// <param name="source">The <see cref="IQueryable"/> to return the first element of.</param>
189
+ /// <param name="predicate">A function to test each element for a condition.</param>
190
+ /// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
191
+ /// <returns>The first element in source that passes the test in predicate.</returns>
192
+ #if NET35
193
+ public static object First ( [ NotNull ] this IQueryable source , [ NotNull ] string predicate , params object [ ] args )
194
+ #else
195
+ public static dynamic First ( [ NotNull ] this IQueryable source , [ NotNull ] string predicate , params object [ ] args )
196
+ #endif
197
+ {
198
+ Check . NotNull ( source , nameof ( source ) ) ;
199
+ Check . NotEmpty ( predicate , nameof ( predicate ) ) ;
200
+
201
+ bool createParameterCtor = source . IsLinqToObjects ( ) ;
202
+ LambdaExpression lambda = DynamicExpression . ParseLambda ( createParameterCtor , source . ElementType , null , predicate , args ) ;
203
+
204
+ return Execute ( _firstPredicate , source , Expression . Quote ( lambda ) ) ;
194
205
}
206
+ private static readonly MethodInfo _firstPredicate = GetMethod ( nameof ( Queryable . First ) , 1 ) ;
207
+ #endregion First
195
208
209
+ #region FirstOrDefault
196
210
/// <summary>
197
211
/// Returns the first element of a sequence, or a default value if the sequence contains no elements.
198
212
/// </summary>
199
213
/// <param name="source">The <see cref="IQueryable"/> to return the first element of.</param>
200
- /// <returns>default(TSource) if source is empty; otherwise, the first element in source.</returns>
214
+ /// <returns>default if source is empty; otherwise, the first element in source.</returns>
201
215
#if NET35
202
216
public static object FirstOrDefault ( [ NotNull ] this IQueryable source )
203
217
#else
@@ -206,11 +220,33 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source)
206
220
{
207
221
Check . NotNull ( source , nameof ( source ) ) ;
208
222
209
- return source . Provider . Execute ( Expression . Call (
210
- typeof ( Queryable ) , "FirstOrDefault" ,
211
- new [ ] { source . ElementType } , source . Expression ) ) ;
223
+ return Execute ( _firstOrDefault , source ) ;
224
+ }
225
+ private static readonly MethodInfo _firstOrDefault = GetMethod ( nameof ( Queryable . FirstOrDefault ) ) ;
226
+
227
+ /// <summary>
228
+ /// Returns the first element of a sequence that satisfies a specified condition or a default value if no such element is found.
229
+ /// </summary>
230
+ /// <param name="source">The <see cref="IQueryable"/> to return the first element of.</param>
231
+ /// <param name="predicate">A function to test each element for a condition.</param>
232
+ /// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
233
+ /// <returns>default if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate.</returns>
234
+ #if NET35
235
+ public static object FirstOrDefault ( [ NotNull ] this IQueryable source , [ NotNull ] string predicate , params object [ ] args )
236
+ #else
237
+ public static dynamic FirstOrDefault ( [ NotNull ] this IQueryable source , [ NotNull ] string predicate , params object [ ] args )
238
+ #endif
239
+ {
240
+ Check . NotNull ( source , nameof ( source ) ) ;
241
+ Check . NotEmpty ( predicate , nameof ( predicate ) ) ;
242
+
243
+ bool createParameterCtor = source . IsLinqToObjects ( ) ;
244
+ LambdaExpression lambda = DynamicExpression . ParseLambda ( createParameterCtor , source . ElementType , null , predicate , args ) ;
245
+
246
+ return Execute ( _firstOrDefaultPredicate , source , Expression . Quote ( lambda ) ) ;
212
247
}
213
- #endregion First/FirstOrDefault
248
+ private static readonly MethodInfo _firstOrDefaultPredicate = GetMethod ( nameof ( Queryable . FirstOrDefault ) , 1 ) ;
249
+ #endregion FirstOrDefault
214
250
215
251
#region GroupBy
216
252
/// <summary>
@@ -460,7 +496,7 @@ public static dynamic Last([NotNull] this IQueryable source)
460
496
/// Returns the last element of a sequence, or a default value if the sequence contains no elements.
461
497
/// </summary>
462
498
/// <param name="source">The <see cref="IQueryable"/> to return the last element of.</param>
463
- /// <returns>default(TSource) if source is empty; otherwise, the last element in source.</returns>
499
+ /// <returns>default if source is empty; otherwise, the last element in source.</returns>
464
500
#if NET35
465
501
public static object LastOrDefault ( [ NotNull ] this IQueryable source )
466
502
#else
@@ -949,7 +985,7 @@ public static dynamic Single([NotNull] this IQueryable source)
949
985
/// in the sequence.
950
986
/// </summary>
951
987
/// <param name="source">A <see cref="IQueryable"/> to return the single element of.</param>
952
- /// <returns>The single element of the input sequence, or default(TSource) if the sequence contains no elements.</returns>
988
+ /// <returns>The single element of the input sequence, or default if the sequence contains no elements.</returns>
953
989
#if NET35
954
990
public static object SingleOrDefault ( [ NotNull ] this IQueryable source )
955
991
#else
@@ -1074,5 +1110,58 @@ public static IQueryable Where([NotNull] this IQueryable source, [NotNull] strin
1074
1110
source . Expression , Expression . Quote ( lambda ) ) ) ;
1075
1111
}
1076
1112
#endregion
1113
+
1114
+ #region Private Helpers
1115
+ // Copied from https://github.com/aspnet/EntityFramework/blob/9186d0b78a3176587eeb0f557c331f635760fe92/src/Microsoft.EntityFrameworkCore/EntityFrameworkQueryableExtensions.cs
1116
+ private static object Execute ( MethodInfo operatorMethodInfo , IQueryable source )
1117
+ {
1118
+ if ( operatorMethodInfo . IsGenericMethod )
1119
+ {
1120
+ operatorMethodInfo = operatorMethodInfo . MakeGenericMethod ( source . ElementType ) ;
1121
+ }
1122
+
1123
+ return source . Provider . Execute ( Expression . Call ( null , operatorMethodInfo , source . Expression ) ) ;
1124
+ }
1125
+
1126
+ private static TResult Execute < TResult > ( MethodInfo operatorMethodInfo , IQueryable source )
1127
+ {
1128
+ if ( operatorMethodInfo . IsGenericMethod )
1129
+ {
1130
+ operatorMethodInfo = operatorMethodInfo . MakeGenericMethod ( source . ElementType ) ;
1131
+ }
1132
+
1133
+ return source . Provider . Execute < TResult > ( Expression . Call ( null , operatorMethodInfo , source . Expression ) ) ;
1134
+ }
1135
+
1136
+ private static object Execute ( MethodInfo operatorMethodInfo , IQueryable source , LambdaExpression expression )
1137
+ => Execute ( operatorMethodInfo , source , Expression . Quote ( expression ) ) ;
1138
+
1139
+ private static object Execute ( MethodInfo operatorMethodInfo , IQueryable source , Expression expression )
1140
+ {
1141
+ operatorMethodInfo = operatorMethodInfo . GetGenericArguments ( ) . Length == 2
1142
+ ? operatorMethodInfo . MakeGenericMethod ( source . ElementType , typeof ( object ) )
1143
+ : operatorMethodInfo . MakeGenericMethod ( source . ElementType ) ;
1144
+
1145
+ return source . Provider . Execute ( Expression . Call ( null , operatorMethodInfo , new [ ] { source . Expression , expression } ) ) ;
1146
+ }
1147
+
1148
+ private static TResult Execute < TResult > ( MethodInfo operatorMethodInfo , IQueryable source , LambdaExpression expression )
1149
+ => Execute < TResult > ( operatorMethodInfo , source , Expression . Quote ( expression ) ) ;
1150
+
1151
+ private static TResult Execute < TResult > ( MethodInfo operatorMethodInfo , IQueryable source , Expression expression )
1152
+ {
1153
+ operatorMethodInfo = operatorMethodInfo . GetGenericArguments ( ) . Length == 2
1154
+ ? operatorMethodInfo . MakeGenericMethod ( source . ElementType , typeof ( TResult ) )
1155
+ : operatorMethodInfo . MakeGenericMethod ( source . ElementType ) ;
1156
+
1157
+ return source . Provider . Execute < TResult > ( Expression . Call ( null , operatorMethodInfo , new [ ] { source . Expression , expression } ) ) ;
1158
+ }
1159
+
1160
+ private static MethodInfo GetMethod < TResult > ( string name , int parameterCount = 0 , Func < MethodInfo , bool > predicate = null ) =>
1161
+ GetMethod ( name , parameterCount , mi => ( mi . ReturnType == typeof ( TResult ) ) && ( ( predicate == null ) || predicate ( mi ) ) ) ;
1162
+
1163
+ private static MethodInfo GetMethod ( string name , int parameterCount = 0 , Func < MethodInfo , bool > predicate = null ) =>
1164
+ typeof ( Queryable ) . GetTypeInfo ( ) . GetDeclaredMethods ( name ) . Single ( mi => ( mi . GetParameters ( ) . Length == parameterCount + 1 ) && ( ( predicate == null ) || predicate ( mi ) ) ) ;
1165
+ #endregion Private Helpers
1077
1166
}
1078
1167
}
0 commit comments