2017-03-09 61 views
5

我在寫一個訪問者,它將查詢轉換爲IQueryable。它使用Aggregate方法與種子null然後使用一些func來轉換它。我的問題是這個null類型是decimal?。但是,我得到一個異常Queryable.Aggregate不能使用空值

'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]]])'' 

一些研究,我發現,這是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) } 
      )); 
} 

我的問題是Expression.Constant(seed)這是nullExpression.Constant將其轉換爲類型的常量object:

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

因此我的new decimal?()轉換成(object) null,我得到這個錯誤。

有沒有解決方法?似乎不可能在.net框架中修復(即使可能,它將在4.7或更高版本中修復)。我會爲此創建一個拉請求,但我相信它不會被接受。

代碼片段重現:

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

使用自定義聚合是不是選擇在你的情況? – Evk

+0

我想你可以修改你的訪問者發出正確的'Expression.Constant'直接調用,而不是使用'Queryable.Aggregate'。 –

+0

@ user1892538嘗試向labmda添加一些邏輯。你會遇到多個演員,這對大型收藏有點緩慢。無論如何,這是做這種事的愚蠢的方式。 –

回答

3

從代碼片段開始再現

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

我想它變成

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

如果你想等價

空收集和

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

包含空

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

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

0

如何:

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) } 
      )); 
} 
+1

你想讓我編輯'System.Core.dll'嗎? –

+0

顯然,這只是BCL方法的固定版本應該如何 - 但您不能僅僅修復MS源代碼。 –

+0

沒有發佈的是OP代碼,除了repro :) –