2017-04-21 64 views
2

我想答案很简单:力LINQ总和返回null

List<int?> intList = new List<int?>(){null, null, null}; 
int? sum = list.Sum(); 
int sum2 = list.Sum(a => a.HasValue ? a.Value : 0); 
int sum3 = list.Sum().Value; 

总和总是返回0,为何为空的需要呢?有没有办法强制linq sum返回null?我在这里错过了什么?

+0

在逻辑上,是如何**总和**项目应该是**不存在的对象**?无论如何,你可以简单地检查'if(intList.All(x => x == null))是否返回null;'。 –

+0

我认为这与关系代数和主要关系数据库的实现有更多共同之处。通常,NULL在大多数聚合函数中被忽略,除了COUNT()是有争议的。我并不是说LINQ遵循关系代数,更多的是关于一组数据的行为。这里有一些历史要点(https://msdn.microsoft.com/en-us/library/aa479863.aspx)。 – andreim

回答

2

这里是Sum()

public static int? Sum(this IEnumerable<int?> source) { 
if (source == null) throw Error.ArgumentNull("source"); 
int sum = 0; 
checked { 
    foreach (int? v in source) { 
     if (v != null) sum += v.GetValueOrDefault(); 
    } 
} 
return sum; 

的理由不返回空的实现是它的实现方式 - 因为结果永远不会返回null,所以使用int sum = 0;

+0

啊,这就是原因。但是,微软为什么会像这样开发Sum。总和总是返回一些值int,decimal,float,.. – broadband

+0

@broadband其实它甚至[记录](https://msdn.microsoft.com/en-us/library/bb156065(v = vs.110).aspx) :*如果源不包含元素,则此方法返回**零**。至于为什么,你应该问MSFTs,对我来说这是一个错误(由于它们的向后兼容策略永远不会被修复),因为相应的'IQueryable '方法在由真实(非LINQ到对象)查询提供程序实现时工作方式不同。 –

+0

@IvanStoev不认为是一个错误。看看来自db世界的一些例子 - SUM和其他聚合函数忽略SqlServer,Oracle,MySql,Postgres,Mongo上的NULL ......似乎有多个玩家走向相同的事情。所以Linq也是这样。因此,可查询提供程序将通过向数据库服务器发出命令来工作,从而获得相同的结果0.唯一的区别在于,如果提供了null与SQL中的SUM()相比,Enumerable.Sum()抛出异常未提供值时返回NULL。 – andreim

1

它只是简单地匹配你的输入类型。如果您将列表更改为List,它将返回int not int ?,因为您的列表是int?这是它返回......

1

你可以试试这个:

int? sum = intList.TrueForAll(x => x == null) ? null : intList.Sum(); 
+0

哇。我在C#的5年经验后,甚至不知道“TrueForAll”方法的存在:D –

+0

我在问为什么Sum返回可为空的类型,因为您总是会获得一些价值。 – broadband

0

由于fubo已经写道:

的理由不返回null是它的实现方式 - 的int sum = 0;使用的结果永远不能返回null。

为什么不写自己的扩展方法

public static int? NullableSum(this IEnumerable<int?> source) 
{ 
    int? sum = null; 
    foreach (int? v in source) 
    { 
     if (v != null) 
     { 
      if (sum == null) 
      { 
       sum = 0; 
      } 

      sum += v.GetValueOrDefault()    
     } 
    } 

    return sum; 
} 
0

你也可以试试这个,如果你的LINQ总和返回null:

int? sum = intList.AsQueryable().Any(a => a.HasValue) ? intList.AsQueryable().Sum(a => a.Value) : (int?)null;