@@ -100,6 +100,60 @@ public static object Aggregate([NotNull] this IQueryable source, [NotNull] strin
100
100
}
101
101
#endregion Aggregate
102
102
103
+ #region All
104
+ private static readonly MethodInfo _AllPredicate = GetMethod ( nameof ( Queryable . All ) , 1 ) ;
105
+
106
+ /// <summary>
107
+ /// Determines whether all the elements of a sequence satisfy a condition.
108
+ /// </summary>
109
+ /// <remarks>
110
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
111
+ /// that All asynchronous operations have completed before calling another method on this context.
112
+ /// </remarks>
113
+ /// <param name="source">
114
+ /// An <see cref="IQueryable" /> to calculate the All of.
115
+ /// </param>
116
+ /// <param name="predicate">A projection function to apply to each element.</param>
117
+ /// <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>
118
+ /// <returns>
119
+ /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.
120
+ /// </returns>
121
+ [ PublicAPI ]
122
+ public static bool All ( [ NotNull ] this IQueryable source , [ NotNull ] string predicate , [ CanBeNull ] params object [ ] args )
123
+ {
124
+ return All ( source , ParsingConfig . Default , predicate , args ) ;
125
+ }
126
+
127
+ /// <summary>
128
+ /// Determines whether all the elements of a sequence satisfy a condition.
129
+ /// </summary>
130
+ /// <remarks>
131
+ /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure
132
+ /// that All asynchronous operations have completed before calling another method on this context.
133
+ /// </remarks>
134
+ /// <param name="source">
135
+ /// An <see cref="IQueryable" /> to calculate the All of.
136
+ /// </param>
137
+ /// <param name="config">The <see cref="ParsingConfig"/>.</param>
138
+ /// <param name="predicate">A projection function to apply to each element.</param>
139
+ /// <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>
140
+ /// <returns>
141
+ /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.
142
+ /// </returns>
143
+ [ PublicAPI ]
144
+ public static bool All ( [ NotNull ] this IQueryable source , [ NotNull ] ParsingConfig config , [ NotNull ] string predicate , [ CanBeNull ] params object [ ] args )
145
+ {
146
+ Check . NotNull ( source , nameof ( source ) ) ;
147
+ Check . NotNull ( config , nameof ( config ) ) ;
148
+ Check . NotEmpty ( predicate , nameof ( predicate ) ) ;
149
+
150
+ bool createParameterCtor = SupportsLinqToObjects ( config , source ) ;
151
+ LambdaExpression lambda = DynamicExpressionParser . ParseLambda ( createParameterCtor , source . ElementType , null , predicate , args ) ;
152
+
153
+ return Execute < bool > ( _AllPredicate , source , Expression . Quote ( lambda ) ) ;
154
+ }
155
+ #endregion AllAsync
156
+
103
157
#region Any
104
158
private static readonly MethodInfo _any = GetMethod ( nameof ( Queryable . Any ) ) ;
105
159
@@ -173,6 +227,79 @@ public static bool Any([NotNull] this IQueryable source, [NotNull] LambdaExpress
173
227
}
174
228
#endregion Any
175
229
230
+ #region Average
231
+ /// <summary>
232
+ /// Computes the average of a sequence of numeric values.
233
+ /// </summary>
234
+ /// <param name="source">A sequence of numeric values to calculate the average of.</param>
235
+ /// <example>
236
+ /// <code language="cs">
237
+ /// IQueryable queryable = employees.AsQueryable();
238
+ /// var result1 = queryable.Average();
239
+ /// var result2 = queryable.Select("Roles.Average()");
240
+ /// </code>
241
+ /// </example>
242
+ /// <returns>The average of the values in the sequence.</returns>
243
+ [ PublicAPI ]
244
+ public static double Average ( [ NotNull ] this IQueryable source )
245
+ {
246
+ Check . NotNull ( source , nameof ( source ) ) ;
247
+
248
+ var average = GetMethod ( nameof ( Queryable . Average ) , source . ElementType , typeof ( double ) ) ;
249
+ return Execute < double > ( average , source ) ;
250
+ }
251
+
252
+ /// <summary>
253
+ /// Computes the average of a sequence of numeric values.
254
+ /// </summary>
255
+ /// <param name="source">A sequence of numeric values to calculate the average of.</param>
256
+ /// <param name="config">The <see cref="ParsingConfig"/>.</param>
257
+ /// <param name="predicate">A function to test each element for a condition.</param>
258
+ /// <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>
259
+ /// <example>
260
+ /// <code language="cs">
261
+ /// IQueryable queryable = employees.AsQueryable();
262
+ /// var result = queryable.Average("Income");
263
+ /// </code>
264
+ /// </example>
265
+ /// <returns>The average of the values in the sequence.</returns>
266
+ [ PublicAPI ]
267
+ public static double Average ( [ NotNull ] this IQueryable source , [ NotNull ] ParsingConfig config , [ NotNull ] string predicate , params object [ ] args )
268
+ {
269
+ Check . NotNull ( source , nameof ( source ) ) ;
270
+ Check . NotNull ( config , nameof ( config ) ) ;
271
+ Check . NotEmpty ( predicate , nameof ( predicate ) ) ;
272
+
273
+ bool createParameterCtor = SupportsLinqToObjects ( config , source ) ;
274
+ LambdaExpression lambda = DynamicExpressionParser . ParseLambda ( config , createParameterCtor , source . ElementType , null , predicate , args ) ;
275
+
276
+ return Average ( source , lambda ) ;
277
+ }
278
+
279
+ /// <inheritdoc cref="Average(IQueryable, ParsingConfig, string, object[])"/>
280
+ [ PublicAPI ]
281
+ public static double Average ( [ NotNull ] this IQueryable source , [ NotNull ] string predicate , [ CanBeNull ] params object [ ] args )
282
+ {
283
+ return Average ( source , ParsingConfig . Default , predicate , args ) ;
284
+ }
285
+
286
+ /// <summary>
287
+ /// Computes the average of a sequence of numeric values.
288
+ /// </summary>
289
+ /// <param name="source">A sequence of numeric values to calculate the average of.</param>
290
+ /// <param name="lambda">A Lambda Expression.</param>
291
+ /// <returns>The average of the values in the sequence.</returns>
292
+ [ PublicAPI ]
293
+ public static double Average ( [ NotNull ] this IQueryable source , [ NotNull ] LambdaExpression lambda )
294
+ {
295
+ Check . NotNull ( source , nameof ( source ) ) ;
296
+ Check . NotNull ( lambda , nameof ( lambda ) ) ;
297
+
298
+ var averageSelector = GetMethod ( nameof ( Queryable . Average ) , lambda . GetReturnType ( ) , typeof ( double ) , 1 ) ;
299
+ return Execute < double > ( averageSelector , source , lambda ) ;
300
+ }
301
+ #endregion Average
302
+
176
303
#region AsEnumerable
177
304
#if NET35
178
305
/// <summary>
@@ -1808,13 +1935,74 @@ public static IQueryable SkipWhile([NotNull] this IQueryable source, [NotNull] s
1808
1935
/// Computes the sum of a sequence of numeric values.
1809
1936
/// </summary>
1810
1937
/// <param name="source">A sequence of numeric values to calculate the sum of.</param>
1938
+ /// <example>
1939
+ /// <code language="cs">
1940
+ /// IQueryable queryable = employees.AsQueryable();
1941
+ /// var result1 = queryable.Sum();
1942
+ /// var result2 = queryable.Select("Roles.Sum()");
1943
+ /// </code>
1944
+ /// </example>
1811
1945
/// <returns>The sum of the values in the sequence.</returns>
1946
+ [ PublicAPI ]
1812
1947
public static object Sum ( [ NotNull ] this IQueryable source )
1813
1948
{
1814
1949
Check . NotNull ( source , nameof ( source ) ) ;
1815
1950
1816
- var optimized = OptimizeExpression ( Expression . Call ( typeof ( Queryable ) , nameof ( Queryable . Sum ) , null , source . Expression ) ) ;
1817
- return source . Provider . Execute ( optimized ) ;
1951
+ var sum = GetMethod ( nameof ( Queryable . Sum ) , source . ElementType ) ;
1952
+ return Execute < object > ( sum , source ) ;
1953
+ }
1954
+
1955
+ /// <summary>
1956
+ /// Computes the sum of a sequence of numeric values.
1957
+ /// </summary>
1958
+ /// <param name="source">A sequence of numeric values to calculate the sum of.</param>
1959
+ /// <param name="config">The <see cref="ParsingConfig"/>.</param>
1960
+ /// <param name="predicate">A function to test each element for a condition.</param>
1961
+ /// <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>
1962
+ /// <example>
1963
+ /// <code language="cs">
1964
+ /// IQueryable queryable = employees.AsQueryable();
1965
+ /// var result = queryable.Sum("Income");
1966
+ /// </code>
1967
+ /// </example>
1968
+ /// <returns>The sum of the values in the sequence.</returns>
1969
+ [ PublicAPI ]
1970
+ public static object Sum ( [ NotNull ] this IQueryable source , [ NotNull ] ParsingConfig config , [ NotNull ] string predicate , params object [ ] args )
1971
+ {
1972
+ Check . NotNull ( source , nameof ( source ) ) ;
1973
+ Check . NotNull ( config , nameof ( config ) ) ;
1974
+ Check . NotEmpty ( predicate , nameof ( predicate ) ) ;
1975
+
1976
+ bool createParameterCtor = SupportsLinqToObjects ( config , source ) ;
1977
+ LambdaExpression lambda = DynamicExpressionParser . ParseLambda ( config , createParameterCtor , source . ElementType , null , predicate , args ) ;
1978
+
1979
+ var sumSelector = GetMethod ( nameof ( Queryable . Sum ) , lambda . GetReturnType ( ) , 1 ) ;
1980
+
1981
+ return Execute < object > ( sumSelector , source , lambda ) ;
1982
+ }
1983
+
1984
+ /// <inheritdoc cref="Sum(IQueryable, ParsingConfig, string, object[])"/>
1985
+ [ PublicAPI ]
1986
+ public static object Sum ( [ NotNull ] this IQueryable source , [ NotNull ] string predicate , [ CanBeNull ] params object [ ] args )
1987
+ {
1988
+ return Sum ( source , ParsingConfig . Default , predicate , args ) ;
1989
+ }
1990
+
1991
+ /// <summary>
1992
+ /// Computes the sum of a sequence of numeric values.
1993
+ /// </summary>
1994
+ /// <param name="source">A sequence of numeric values to calculate the sum of.</param>
1995
+ /// <param name="lambda">A Lambda Expression.</param>
1996
+ /// <returns>The sum of the values in the sequence.</returns>
1997
+ [ PublicAPI ]
1998
+ public static object Sum ( [ NotNull ] this IQueryable source , [ NotNull ] LambdaExpression lambda )
1999
+ {
2000
+ Check . NotNull ( source , nameof ( source ) ) ;
2001
+ Check . NotNull ( lambda , nameof ( lambda ) ) ;
2002
+
2003
+ var sumSelector = GetMethod ( nameof ( Queryable . Sum ) , lambda . GetReturnType ( ) , 1 ) ;
2004
+
2005
+ return Execute < object > ( sumSelector , source , lambda ) ;
1818
2006
}
1819
2007
#endregion Sum
1820
2008
@@ -2056,13 +2244,6 @@ private static void CheckOuterAndInnerTypes(ParsingConfig config, bool createPar
2056
2244
// If types are not the same, try to convert to Nullable and generate new LambdaExpression
2057
2245
if ( outerSelectorReturnType != innerSelectorReturnType )
2058
2246
{
2059
- //var outerSelectorReturnTypeInfo = outerSelectorReturnType.GetTypeInfo();
2060
- //var innerSelectorReturnTypeInfo = innerSelectorReturnType.GetTypeInfo();
2061
- //if (outerSelectorReturnTypeInfo.BaseType == typeof(DynamicClass) && innerSelectorReturnTypeInfo.BaseType == typeof(DynamicClass))
2062
- //{
2063
-
2064
- //}
2065
-
2066
2247
if ( TypeHelper . IsNullableType ( outerSelectorReturnType ) && ! TypeHelper . IsNullableType ( innerSelectorReturnType ) )
2067
2248
{
2068
2249
innerSelectorReturnType = ExpressionParser . ToNullableType ( innerSelectorReturnType ) ;
@@ -2125,7 +2306,9 @@ private static TResult Execute<TResult>(MethodInfo operatorMethodInfo, IQueryabl
2125
2306
}
2126
2307
2127
2308
var optimized = OptimizeExpression ( Expression . Call ( null , operatorMethodInfo , source . Expression ) ) ;
2128
- return source . Provider . Execute < TResult > ( optimized ) ;
2309
+ var result = source . Provider . Execute ( optimized ) ;
2310
+
2311
+ return ( TResult ) Convert . ChangeType ( result , typeof ( TResult ) ) ;
2129
2312
}
2130
2313
2131
2314
private static object Execute ( MethodInfo operatorMethodInfo , IQueryable source , LambdaExpression expression )
@@ -2151,14 +2334,22 @@ private static TResult Execute<TResult>(MethodInfo operatorMethodInfo, IQueryabl
2151
2334
: operatorMethodInfo . MakeGenericMethod ( source . ElementType ) ;
2152
2335
2153
2336
var optimized = OptimizeExpression ( Expression . Call ( null , operatorMethodInfo , source . Expression , expression ) ) ;
2154
- return source . Provider . Execute < TResult > ( optimized ) ;
2337
+ var result = source . Provider . Execute ( optimized ) ;
2338
+
2339
+ return ( TResult ) Convert . ChangeType ( result , typeof ( TResult ) ) ;
2155
2340
}
2156
2341
2157
2342
private static MethodInfo GetGenericMethod ( string name )
2158
2343
{
2159
2344
return typeof ( Queryable ) . GetTypeInfo ( ) . GetDeclaredMethods ( name ) . Single ( mi => mi . IsGenericMethod ) ;
2160
2345
}
2161
2346
2347
+ private static MethodInfo GetMethod ( string name , Type argumentType , Type returnType , int parameterCount = 0 , Func < MethodInfo , bool > predicate = null ) =>
2348
+ GetMethod ( name , returnType , parameterCount , mi => mi . ToString ( ) . Contains ( argumentType . ToString ( ) ) && ( ( predicate == null ) || predicate ( mi ) ) ) ;
2349
+
2350
+ private static MethodInfo GetMethod ( string name , Type returnType , int parameterCount = 0 , Func < MethodInfo , bool > predicate = null ) =>
2351
+ GetMethod ( name , parameterCount , mi => ( mi . ReturnType == returnType ) && ( ( predicate == null ) || predicate ( mi ) ) ) ;
2352
+
2162
2353
private static MethodInfo GetMethod ( string name , int parameterCount = 0 , Func < MethodInfo , bool > predicate = null )
2163
2354
{
2164
2355
try
@@ -2168,7 +2359,7 @@ private static MethodInfo GetMethod(string name, int parameterCount = 0, Func<Me
2168
2359
}
2169
2360
catch ( Exception ex )
2170
2361
{
2171
- throw new Exception ( "Method not found: " + name , ex ) ;
2362
+ throw new Exception ( "Specific method not found: " + name , ex ) ;
2172
2363
}
2173
2364
}
2174
2365
#endregion Private Helpers
0 commit comments