C# 为什么一系列可为null的对象的Linq和本身是可为null的?

C# 为什么一系列可为null的对象的Linq和本身是可为null的?,c#,linq,sum,nullable,base-class-library,C#,Linq,Sum,Nullable,Base Class Library,通常,int?表示System.Nullable(或System.Nullable`1[System.Int32]) 假设您有一个内存中的IEnumerable(例如列表),让我们称之为seq;然后,您可以通过以下公式找到其总和: var seqSum = seq.Sum(); 当然,这涉及到扩展方法重载,它实际上是System.Linq.Enumerable上的一个静态方法 但是,该方法从不返回null,那么,即使seq是空集合,或者更一般地说是所有元素都是null类型int?的值的集合,为

通常,
int?
表示
System.Nullable
(或
System.Nullable`1[System.Int32]

假设您有一个内存中的
IEnumerable
(例如
列表
),让我们称之为
seq
;然后,您可以通过以下公式找到其总和:

var seqSum = seq.Sum();
当然,这涉及到扩展方法重载,它实际上是
System.Linq.Enumerable
上的一个静态方法

但是,该方法从不返回
null
那么,即使
seq
是空集合,或者更一般地说是所有元素都是
null
类型
int?
的值的集合,为什么返回类型仍声明为
null
,所讨论的
Sum
方法仍然返回零,而不是
null

这从文档中以及System.Core.dll源代码中都可以看出:

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; 
} 
公共静态int?Sum(此IEnumerable源){
if(source==null)抛出错误.ArgumentNull(“source”);
整数和=0;
选中{
foreach(int?v在源代码中){
如果(v!=null)和+=v.GetValuerDefault();
} 
} 
回报金额;
} 
请注意,只有一个
return
语句,其表达式
sum
的类型为
int
(然后通过包装将其隐式转换为
int?

总是包装返回值似乎很浪费。(如果需要,调用方始终可以隐式地在其一侧进行包装。)

此外,此返回类型可能会导致调用方编写代码,例如
if(!seqSum.HasValue){/*逻辑来处理此*/}
,这实际上是不可访问的(C#编译器无法知道的事实)

那么,为什么这个返回参数不能简单地声明为
int
,并且不能为null呢?


我想知道与(在
System.Linq.Queryable
类中)具有相同的返回类型是否有任何好处。如果有LINQ提供程序(可能是LINQ到SQL?)实现此方法,则后一种方法在实践中可能返回
null

有几条评论提到,这并不是真正可以回答的问题(或者只是基于意见,没有官方回应)。我不会争辩的。然而,人们仍然可以对可用的代码进行分析,形成足够强大的理论。我的想法很简单,这是一种现有的MS模式

如果查看
System.Linq.Enumerable
的其余部分,尤其是与数学相关的函数,您会发现一种模式,即返回与输入参数相同的类型,除非返回具有不同类型的特定原因

请参见以下功能:

Max()

Sum()

您可以看到,它仍然保留
Nullable
类型,但是必须将返回类型更改为合适的类型,以支持将整数平均在一起得到的结果

但是,当您进一步查看
平均值
时,您会看到以下内容:

public static float Average(this IEnumerable<float> source);
public static float? Average(this IEnumerable<float?> source);
我再提一次,这就是所谓的“意见回答”。我已经寻找了任何MS最佳实践或语言规范信息,这些信息可能暗示这是MS用来支持我的分析的语言模式,但我找不到任何东西。也就是说,如果您查看.Net核心库中的各个位置,尤其是
System.Collections.Generic
命名空间,您将看到除非有特定原因,否则返回类型与集合类型匹配


当涉及到
Nullable
类型时,我认为没有理由偏离该规则。

我猜应该继续使用
Sum
的格式,返回与求和相同的类型。但最终只有一个C#设计人员能够回答这个问题。与
Queryable
对等也是我唯一能想到的。您可以说它从不返回
null
:更好的问题是,为什么要检查
null
,然后使用
GeValueOrDefault
?@juharr:因为它比其他方法更有效,它不需要检查是否有值,它只返回字段
value
@juharr
==null
/
=空的
on
Nullable
只是语言技巧;它编译成一个
.HasValue
testI确认观察结果。可能有倾向于返回相同的“类型”。但还要注意,对于空(count-0)源未定义的
Max
Min
Average
,在这种情况下实际上将返回
null
。但只能使用一系列可为null的值;在不可为null的情况下,这些方法将在一个空的输入序列上发生异常。假设原始(不可为空)
Max
(等…)在列表为空时抛出异常。我的期望是要么抛出与原始异常类似的异常,要么像这里的情况一样,返回一个空的
Nullable
。我希望,因为在正常情况下,对空集执行的操作没有值,因此它们本身就是空的
Sum
有点不同,因为您从值0开始,并使用集合的内容执行数学运算。如果集合为空,则仍有0。如果集合包含一个空值列表,仍然是0。换句话说,一个空集合的最大值是多少?现在,一个空组加在一起的值是多少?
public static int Min(this IEnumerable<int> source);
public static int? Min(this IEnumerable<int?> source);
public static long Min(this IEnumerable<long> source);
public static long? Min(this IEnumerable<long?> source);
public static int Sum(this IEnumerable<int> source);
public static int? Sum(this IEnumerable<int?> source);
public static long Sum(this IEnumerable<long> source);
public static long? Sum(this IEnumerable<long?> source);
public static double Average(this IEnumerable<int> source);
public static double? Average(this IEnumerable<int?> source);
public static float Average(this IEnumerable<float> source);
public static float? Average(this IEnumerable<float?> source);
public static int Abs(int value);
public static long Abs(long value);

public static int Max(int val1, int val2);
public static long Max(long val1, long val2);