【问题标题】:C# Regex.Matches and nullability issueC# Regex.Matches 和可空性问题
【发布时间】:2019-11-14 19:24:10
【问题描述】:

我正在使用启用了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 的文档说它将返回一个空集合,而不是 null。

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

【问题讨论】:

  • 能否请您发布 ownerStringwwids 的初始化
  • 更新了问题以显示 ownerString 可以为空。即使我在Regex.Matches 中将ownerString 替换为"",我仍然会收到错误消息。

标签: c# nullable c#-8.0


【解决方案1】:

问题在于MatchCollection 实现了非泛型IList 接口而不是泛型IList&lt;Match&gt; 接口,以实现向后兼容,而IEnumerator.Current 被定义为object?,所以foreach 实际上将此可为空的对象转换为不可为空的Match。就好像你写的一样

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

这一切都来自于我们在 C# 2 之前很久被遗忘的时代,而现在又回到了 C# 8 中。

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

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();

【讨论】:

  • 很好的答案! foreach (var match in matches.OfType&lt;Match&gt;()) 也可以吗?因为那是我通常做的,但我还没有机会使用 C# 8。
  • @AhmedAbdelhameed:当然,这行得通,但.OfType&lt;&gt; 实际上是一个过滤器——它返回该类型的所有元素,而忽略其他元素。当然在这种情况下它们总是匹配的,但是如果你知道这一点,一个更有效的表达是使用.Cast&lt;&gt;,如果不匹配就会抛出。在这种情况下我都不会使用,因为MatchCollection 实际上确实实现了IEnumerable&lt;Match&gt;——它并不严格需要强制转换,不像只实现IEnumerable 的集合。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多