【问题标题】:Foreach variable not null after check still gives warning检查后 Foreach 变量不为空仍然给出警告
【发布时间】:2022-01-22 22:35:10
【问题描述】:

查看此示例:

var list = new List<string?>();

foreach (string item in list.Where(i => i != null))
{
    if (item.Length == 2)
    {
        ...
    }
}

在这个示例中,我在两个地方得到了可能的空引用。 foreach 变量和 Lengthif 中的取消引用。第二个我可以通过添加一个该死的(null-forgiving)运算符来轻松修复,如下所示:item!.Length

有没有办法对第一个做同样的事情?我知道我可以将其标记为可空字符串并再次检查,但是我已经检查过了。

【问题讨论】:

  • 试试这个 foreach (string? item in list.Where(i => i != null)) 或更好的 foreach (var item in list.Where(i => i != null))
  • 是的,这将删除即时警告,但是当我已经检查时,我必须稍后检查该字符串的可空性。我需要一些机制来告诉编译器这个foreach 变量不为空。
  • 除了下面的正确答案之外,我还有一个问题:为什么要创建一个包含可为空字符串的列表,因为它已经可以为空?
  • @riffnl 这只是一个示例。我的实际代码不同。但在新的 C# 10 和 .Net 6 表示法字符串(或与此相关的任何其他引用类型)默认情况下不可为空。这意味着您不能将 null 分配给它。它仍然是一个警告,但很快就会出错。

标签: c# .net .net-6.0 nullable-reference-types


【解决方案1】:

当您使用 Where 应用过滤时,您会消除所有空值,但这不会更改值的类型。
您只需将过滤后的结果转换为正确的类型:

foreach (string item in list.Where(i => i != null).Select(x => x!))

【讨论】:

  • 好答案。我自己应该想到的 :))
【解决方案2】:

不幸的是,Where 谓词不会修改调用者对可枚举项是否为空的看法。

approach given by Dmitry 涉及额外的运行时开销,因为使用了额外的 Select 调用。

您可以通过这种扩展方法避免这种开销:

public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : class
{
    foreach (T? item in source)
    {
        if (item != null)
            yield return item;
    }
}

然后你的代码变成:

foreach (string item in list.WhereNotNull())
{
    if (item.Length == 2)
    {
        ...
    }
}

【讨论】:

    猜你喜欢
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 2019-08-13
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    相关资源
    最近更新 更多