C# Regex.Matches 和可空性问题

C# Regex.Matches and nullability issue

我正在使用启用了 nullable 的 C# 8,现在我的正则表达式循环出现问题:

public static async Task<IEnumerable<WorkerDto>?> GetOwnersAsync(LampContext context, string? ownerString)
{
    if (string.IsNullOrWhiteSpace(ownerString))
        return null;

    var wwids = new List<int>();

    var matches = Regex.Matches(ownerString, @"\d+");
    foreach (Match match in matches)
        wwids.Add(int.Parse(match.Value));

它说我可能对 match 迭代变量进行了空引用赋值,我不确定为什么会这样说,或者如何绕过它。 Matches 的文档说它将 return 一个空集合,而不是 null。

我现在应该如何编写该代码?

问题是 MatchCollection 优先于通用 IList<Match> 接口实现非通用 IList 接口,为了向后兼容,IEnumerator.Current 定义为object?,因此 foreach 实际上将此可为 null 的对象强制转换为不可为 null 的 Match。就好像你写了

foreach (object o? in matches) {
    Match match = (Match) o;
    ...
}

所有这些都来自我们拥有 C# 2 之前被遗忘已久的时间,现在又回来咬我们的 C# 8。

有几种有效的解决方法;最简单的方法之一是将 matches 分配给 IList<Match>IEnumerable<Match> 类型的变量(因为它确实实现了通用接口):

IList<Match> matches = Regex.Matches(ownerString, @"\d+");
foreach (Match match in matches)
    wwids.Add(int.Parse(match.Value));

请注意,我们在这里不需要强制转换。另一种是使用.AsEnumerable()来有效地施放它:

var matches = Regex.Matches(ownerString, @"\d+");
foreach (Match match in matches.AsEnumerable())
    wwids.Add(int.Parse(match.Value));

最后但同样重要的是,如果您所做的只是 .Add 将这些值添加到一个新列表中,您不妨使用 LINQ 一次性构建该列表:

var wwids = matches.Select(m => int.Parse(m.Value)).ToList();