Queryable.Aggregate不使用空值

Ale*_*kiy 5 .net c# linq iqueryable linq-expressions

我正在写一个转换IQueryable查询的访问者.它使用Aggregate种子方法,null然后使用一些函数来转换它.我的问题是这个null是类型的decimal?.但我得到一个例外

'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]]])''
Run Code Online (Sandbox Code Playgroud)

经过一些研究后,我发现它Aggregate本身就在破坏我的查询:

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) }
            ));
}
Run Code Online (Sandbox Code Playgroud)

我的问题是与Expression.Constant(seed)这是nullExpression.Constant它转换为对象的类型恒定:

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

因此我new decimal?()转换成了(object) null我得到这个错误.

这有什么解决方法吗?似乎不可能在.net框架中修复(即使它可能,它将在4.7或更高版本中修复).我会为此创建一个拉取请求,但我确信它不会被接受.

要重现的代码段:

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

小智 3

从代码片段开始重现

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

我会把它改成

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

如果您想要等值金额

与空集合

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

包含空值

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

基本上,我建议使用DefaultIfEmpty().Aggregate