Как обычно, int? означает System.Nullable<int> (или System.Nullable`1[System.Int32]).
Предположим, что у вас есть встроенная память IEnumerable<int?> (например, List<int?>), назовем ее seq; то вы можете найти его сумму с помощью:
var seqSum = seq.Sum();
Конечно, это относится к перегрузке метода расширения int? IEnumerable<int?>.Sum() (документация), которая действительно является статическим методом на System.Linq.Enumerable.
Однако метод никогда не возвращает null, , поэтому почему тип возврата объявлен как Nullable<>? Даже в тех случаях, когда seq представляет собой пустую коллекцию или, в общем, коллекцию, все чьими элементами являются null значение типа 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;
}
Обратите внимание, что существует только один оператор return, и его выражение Sum имеет тип int (который затем будет неявно преобразован в int? путем обертывания).
Кажется расточительным всегда обертывать возвращаемое значение. (При желании вызывающий абонент всегда мог сделать обертку неявно на его стороне.)
Кроме того, этот тип возврата может привести вызывающего пользователя к написанию кода, такого как if (!seqSum.HasValue) { /* logic to handle this */ }, который в действительности будет недоступен (факт, о котором компилятор С# не может знать).
Итак, почему этот возвращаемый параметр не просто объявлен как int без значения NULL?
Интересно, есть ли какая-либо выгода от того же типа возврата, что и int? IQueryable<int?>.Sum() (в классе System.Linq.Queryable). Этот последний метод может возвращать null на практике, если есть поставщики LINQ (возможно, LINQ to SQL?), Которые его реализуют.