Queryable.Aggregate does not work with null values

I am writing a visitor that converts an IQueryable query. It uses the Aggregate method with seed null , and then uses some func to convert it. My problem is that this zero is of type decimal? . But I get an exception

 'Expression of type 'System.Object' cannot be used for parameter of type 'System.Nullable`1[System.Decimal]' of method 'System.Nullable`1[System.Decimal] Aggregate[Nullable`1,Nullable`1] (System.Linq.IQueryable`1[System.Nullable`1[System.Decimal]], System.Nullable`1[System.Decimal], System.Linq.Expressions.Expression`1[System.Func`3[System.Nullable`1[System.Decimal], System.Nullable`1[System.Decimal],System.Nullable`1[System.Decimal]]])'' 

After some research, I discovered that he is Aggregate himself, which destroys my request:

 public static TAccumulate Aggregate<TSource,TAccumulate>(this IQueryable<TSource> source, TAccumulate seed, Expression<Func<TAccumulate,TSource,TAccumulate>> func) { if (source == null) throw Error.ArgumentNull("source"); if (func == null) throw Error.ArgumentNull("func"); return source.Provider.Execute<TAccumulate>( Expression.Call( null, GetMethodInfo(Queryable.Aggregate, source, seed, func), new Expression[] { source.Expression, Expression.Constant(seed), Expression.Quote(func) } )); } 

My problem is Expression.Constant(seed) , which is null and Expression.Constant convert it to an object constant like:

 public static ConstantExpression Constant(object value) { return ConstantExpression.Make(value, value == null ? typeof(object) : value.GetType()); } 

So my new decimal?() converted to (object) null , and I get this error.

Is there a workaround for this? It seems impossible to get the patch in the .net framework (and even if possible, it will be fixed in 4.7 or later). I am creating a transfer request, but I am sure that it will not be accepted.

code snippet to play:

 var result = new int?[] {1}.AsQueryable().Aggregate(default(int?), (a, b) => b); 
+5
source share
2 answers

Starting with a snippet of code to play

 var result = new int?[] {1}.AsQueryable().Aggregate(default(int?), (a, b) => b); 

I would change it to

 var result2 = new int?[] {1}.AsQueryable().DefaultIfEmpty().Aggregate((a, b) => b); 

If you need an equivalent amount

with an empty collection

 var result3 = new int?[0].AsQueryable().DefaultIfEmpty().Aggregate( (a, b) => a.GetValueOrDefault() + b.GetValueOrDefault()); 

containing null

 var result4 = new int?[]{1,2,null}.AsQueryable().DefaultIfEmpty().Aggregate( (a, b) => a.GetValueOrDefault() + b.GetValueOrDefault()); 

Basically, I suggest using DefaultIfEmpty().Aggregate

+3
source

How about this:

 public static TAccumulate Aggregate<TSource,TAccumulate>(this IQueryable<TSource> source, TAccumulate seed, Expression<Func<TAccumulate,TSource,TAccumulate>> func) { if (source == null) throw Error.ArgumentNull("source"); if (func == null) throw Error.ArgumentNull("func"); return source.Provider.Execute<TAccumulate>( Expression.Call( null, GetMethodInfo(Queryable.Aggregate, source, seed, func), new Expression[] { source.Expression, Expression.Constant(seed, typeof(TAccumulate)), Expression.Quote(func) } )); } 
0
source

Source: https://habr.com/ru/post/1265241/


All Articles