在 Net Core 6 中解决 values1.Count 上的 "Nullable value type may be null"

Solve "Nullable value type may be null" on values1.Count in NetCore 6

在项目定义中使用 NetCore 6 和 <Nullable>enable</Nullable> 我有:

protected Boolean CrossBelow<T>(IList<Nullable<T>> values1, IList<Nullable<T>> values2) where T : struct, IComparable {

  if (values1[values1.Count - 2] == null || values1.Last() == null || values2[values1.Count - 2] == null || values2.Last() == null)
    return false;

  return values1[values1.Count - 2].Value.CompareTo(values2[values2.Count - 2].Value) > 0 && values1.Last().Value.CompareTo(values2.Last().Value) < 0;

} 

但我收到警告:

Nullable value type may be null

在一些地方,例如:

values1[values1.Count - 2]

我可以使用以下方法解决部分问题:

values1?[values1.Count - 2]

但是我得到了编译错误

`cannot convert from 'int?' to 'int'` 

在 values1.Count 上尝试相同时:

values1?[values1?.Count - 2]

如何解决?

诸如此类的事情:

values1[values1.Count - 2]

values1.Last();

基本上是函数调用,编译器无法确定它们在后续调用中产生相同的值(比如你第一次调用 Last() 它可能 return 不为空,但第二次它 returns null,编译器无法知道在你的情况下这是不可能的)。只需引入变量,即使没有这些警告也不会造成伤害:

protected Boolean CrossBelow<T>(IList<Nullable<T>> values1, IList<Nullable<T>> values2) where T : struct, IComparable
{
    var v1Prev = values1[values1.Count - 2];
    var v1Last = values1.Last();
    var v2Prev = values2[values2.Count - 2];
    var v2Last = values2.Last();
    if (v1Prev == null || v1Last == null || v2Prev == null || v2Last == null)
        return false;

    return v1Prev.Value.CompareTo(v2Prev.Value) > 0 && v1Last.Value.CompareTo(v2Last.Value) < 0;
}

问题是您正在直接访问 Nullable<T>Value 属性。编译器不知道列表中最后一个和倒数第二个索引处的值是否可能在空检查之间以及您在 return 语句中访问这些元素时发生变化。

此处最简单的解决方案是使用 null-conditional operator ?.。这将允许您甚至删除显式空检查,因为现在一切都一次性发生:

protected bool CrossBelow<T>(IList<T?> values1, IList<T?> values2) where T : struct, IComparable =>
       values1[^2]?.CompareTo(values2[^2]) > 0
    && values1[^1]?.CompareTo(values2[^1]) < 0;

我还使用 indices.

简化了您的数组访问

那么上面的代码发生了什么?

你的方法需要两个 ILists values1values2,它们包含 T? 的值(与 Nullable<T> 相同,只是更短) .请注意 IList 实例本身不能为空(或者至少我们不希望它们为空)。因此我们在列表本身之后不需要任何空条件。所以 values1?[values1.Count - 2]values1 之后的 ? 是不需要的。您收到警告的原因是索引操作 returned 的元素可能为空。因此,我们应用 ? 运算符 我们索引了我们想要的元素之后。

多亏了 ?. 运算符,如果前一个索引操作的值 return 不为空,现在只会继续执行 CompareTo() 语句。由于 CompareTo(object? obj) 无论如何都采用可为空的值,因此我们不需要对比较对象进行空检查。如果由 values1[^2] 编辑的值 return(访问倒数第二个元素) null 那么 CompareTo() 将不会被评估并且 null > 0 int? 的计算结果始终为 false。这就是为什么我们不需要在 if 语句中进行显式空值检查的原因。

第二行完全一样。请注意,intnull 的任何比较都会 return false。所以 null < 0 是假的。