对具有未初始化的可为空类型的可枚举最小值和最大值扩展方法行为感到困惑
本文关键字:方法 扩展 最大值 枚举 初始化 类型 最小值 | 更新日期: 2023-09-27 18:31:06
有人可以阐明(或自由推测)为什么Linq Min和Max扩展方法在处理未初始化的可为空类型时的行为方式?
也许最简单的方法是展示我观察到的:
int? a = null;
int? b = 1;
Nullable.Compare(a, b); // -1, indicating null is smaller then 1
new int?[] { null, 1 }.OrderBy(x => x).First(); // null, null smaller then 1
new[] { 0, 1 }.Min(); // 0 as expected
new int[] { }.Min(); // invalidoperator exception as expected
到目前为止一切顺利,但是...
new int?[] { null, 1 }.Max(); // 1 as expected
new int?[] { null, 1 }.Min(); // 1 ?????, why not null ?
new int?[] { null, null }.Min(); // null, why null now and not above ?
new int?[] { }.Min(); // null, and no exception ???
我承认,我一开始并不特别关心 Nullable 类型,但那是另一回事了:-)
我仍然很好奇为什么以这种方式实现它......
干杯巴特
您可以反编译 Nullable 源代码,这将产生以下定义:
public static int Compare<T>(Nullable<T> n1, Nullable<T> n2) where T : struct
{
if (n1.HasValue) {
if (n2.HasValue) return Comparer<T>.Default.Compare(n1.value, n2.value);
return 1;
}
if (n2.HasValue) return -1;
return 0;
}
看起来 nullable.compare 方法故意在 n1 为 null 且 n2 具有值的情况下返回 -1。
同样,您可以反编译 linq 源代码,这将产生以下定义:
public static int? Min(this IEnumerable<int?> source) {
if (source == null) throw Error.ArgumentNull("source");
int? value = null;
foreach (int? x in source) {
if (value == null || x < value)
value = x;
}
return value;
}
对源对象的迭代检查值是否为 null,如果是,则将 x 分配给值*。这只是 linq 的默认实现,用于在与 null 进行比较期间返回一个数字作为最小值。
至于为什么这样做的问题,我认为这是因为 null 表示缺少值而不是整数值,他们(编写 linq 的人)不同意最初构建可比的方式。他们可能没有发现正常的执行路径,其中 null 被认为是"这个 null 和 int 列表的最小值是多少"的最佳答案。