请考虑以下事项:
var emptyValueList = new List<int>(); //any value type (long, float, any struct ...)
var minimum = emptyValueList.Min();
这将抛出InvalidOperationException
(序列不包含元素)。
现在让我们尝试使用引用类型:
var emptyReferenceList = new List<object>(); //any ref type will do such as object ...
var minimum = emptyReferenceList.Min();
这不会抛出并返回null
。好像第default
个操作符被调用第二个案例而不是第一个案例。它适用于可空类型(例如int?
,即使它们是值类型)。
我想知道为什么会这样,如果背后有一个具体的推理?
答案 0 :(得分:6)
这是一个设计决定,我们将不得不向BCL的作者询问。
Min
extension method有各种重载。对于允许null
的类型,我相信Min
会在搜索最小值时跳过所有null
值。这适用于两种引用类型和type Nullable<>
(在您的示例Nullable<int>
中),它不是引用类型,但允许null
(Min
方法决定忽略)。
因此,对于不可为空的结构,Min
的作者可能认为它会是危险的&#34;返回default(TSource)
,因为在其他情况下(通常是数字0
),这可能是有意义的(即非空)最小值,因此输出可能会被误解。
对于允许null
的类型,由于作者选择跳过源自null
的值,因此可以安全地假设仅当序列除了{之外的任何内容时才返回null
{1}}值(包括en empty source的情况)。
请注意,对于可空类型或引用类型,在标准null
下,IComparer<>
值小于任何非空值。对于排序算法(如null
使用的算法), order 必须是完全且可传递的。因此,我们得到:
List<>.Sort
Console.WriteLine(
Comparer<int?>.Default.Compare(null, 7)
); // "-1"
Console.WriteLine(
Nullable.Compare((int?)null, 7)
); // "-1"
Console.WriteLine(
new List<int?> { 9, null, 7, 13, }
.OrderBy(ni => ni).First()
); // ""
// 'Min' is special in that it disregards 'null' values
Console.WriteLine(
new List<int?> { 9, null, 7, 13, }
.Min()
); // "7"
对于真正的引用类型的工作方式相同,例如System.Version
(Min
类型):
class
答案 1 :(得分:0)
您也可以考虑使用扩展程序:
using System.Linq;
public static class EnumerableExtensions {
public static X MinOrDefault<T, X>(this IEnumerable<T> that, Func<T, X> minXp, X defaultValue) {
if (that.Any())
return that.Min(minXp);
else
return defaultValue;
}
}
...
var emptyValueList = new List<int>();
var minimum = emptyValueList.MinOrDefault(e => e, 0);
var emptyEmployeeList = new List<Employee>();
var minimumSalary = emptyEmployeeList.MinOrDefault(e => e.Salary, 0);