c# – 为什么一个可空的序列的Linq-to-Objects总和本身可以为空?

像往常一样,int?表示System.Nullable< int> (或System.Nullable`1 [system.int32]).

假设你有一个内存中的IEnumerable< int?> (例如List< int?>例如),让我们称之为seq;那么你可以找到它的和:

var seqSum = seq.Sum();

当然,这是扩展方法重载int? IEnumerable<int?>.Sum() (documentation),这是System.Linq.Enumerable上的静态方法.

但是,该方法从不返回null,所以为什么返回类型被声明为Nullable?即使在seq是空集合的情况下,或更一般地,集合的所有元素都是类型为int的空值,则所述的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类型(然后将隐式地通过换行转换为int?).

总是包装返回值似乎很浪费. (如果需要的话,呼叫者可以总是在他身边隐含地进行包装)

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

那么为什么这个返回参数不会简单地声明为int,不能为空?

我想知道是否有与int? IQueryable<int?>.Sum()(在System.Linq.Queryable类中)具有相同返回类型的任何好处.如果有LINQ提供程序(也许LINQ to sql?)实现它,后一种方法在实践中可能返回null.

解决方法

几个意见都提到,这不是真正的问题(或者只是基于没有官方回应的意见).我不会争辩然而,仍然可以对可用代码进行分析,并形成一个足够强大的理论.我只是说这是一个现有的MS模式.

如果您查看System.Linq.Enumerable的其余部分,特别是数学相关函数,您将开始看到一种具有返回与输入参数相同类型的趋势的模式,除非返回值具有特定的原因不同的类型

请参阅以下功能

MAX():

public static int Max(this IEnumerable<int> source);
public static int? Max(this IEnumerable<int?> source);
public static long Max(this IEnumerable<long> source);
public static long? Max(this IEnumerable<long?> source);

MIN():

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);

你可以看到它仍然保留了Nullable T类型,但返回类型必须被更改为合适的类型,以支持平均整数一起产生的结果.

当您进一步了解Average时,您会看到以下内容

public static float Average(this IEnumerable<float> source);
public static float? Average(this IEnumerable<float?> source);

再次,回到与原始传入类型返回相同类型的认模式.

现在我们在这里看到这个模式,我们来看看我们是否看到其他地方,让我们来看看System.Math,因为我们在这个问题上.

再次,这里我们看到使用相同返回类型的相同模式:

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);

我会再提一次,这是相当于一个“意见回答”.我已经看过了,可能在这是为MS备份我的分析语言模式暗示任何MS最佳做法或语言规范信息,但我无法找到任何东西.话虽如此,如果您查看.Net核心库中的各种位置,特别是System.Collections.Generic命名空间,您将看到除非有特定的原因,否则返回类型与集合类型相匹配.

我认为没有理由将这个规则从Nullable< T>类型.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...