当枚举MatchCollection时,为什么变量的类型是Object而不是Match类型?

20

我注意到以下代码中似乎有些奇怪:

MatchCollection mc = Regex.Matches(myString, myPattern);
foreach(var match in mc)
    Console.WriteLine(match.Captures[0]); // <-- this line is invalid, unless I replace 'var' above with 'Match'

变量match的类型为Object而不是Match。我通常使用var来枚举集合,没有出现这样的问题。为什么MatchCollection会有所不同?

3个回答

30

MatchCollection是在.NET 2之前编写的,因此它只实现了IEnumerable而不是IEnumerable<T>。但是,你可以使用Cast来轻松解决这个问题:

foreach(var match in mc.Cast<Match>())
如果您为变量指定了明确的类型,就像这样:
foreach(Match match in mc)

如果您使用的是C#编译器,它会自动为每个项插入一个强制转换。在C# 1中需要这样做以避免代码中到处都是强制转换。

(逻辑上,即使使用var也涉及到一种转换——但它总是从一种类型到相同的类型,因此实际上不需要发出任何指令。)有关详细信息,请参阅C# 4规范的8.8.4节。


2
让你想知道为什么在发布 .NET > v2 时,他们没有像其他集合类型一样实现 IEnumerable<Match> 这个简单的步骤。 - Jamiec
@Jamiec:除了在新类中实现的集合类型,他们实际上更新了哪些集合类型?稍后开始实现接口可能会涉及到一些微妙的问题。请注意,同样的情况也发生在其他地方,例如 DataTable。 - Jon Skeet
谢谢@Jon,我很惊讶之前没有遇到过这个问题。有兴趣了解你所提到的一些微妙问题,但也许这不是合适的地方... - D'Arcy Rittich
@Jon - 假设是所有糟糕问题的根源。回头看我认为已经更新的那些代码,我发现它们要么没有被更新(例如 DataTable),要么在 2.0 之前就不存在。 - Jamiec
1
@Jon:SO最好的地方。谢谢Jon。那正是我的问题,也正是我的疑问和我所需要的答案。但我确实想知道为什么<T>没有被实现,只是为了保持一致性。 - david.pfx
显示剩余2条评论

1

试试这个:

foreach(Match match in mc)

由于MatchCollection没有实现IEnumerable<T>,所以在foreach中的枚举器将为序列中的每个Match接收一个object。你需要将对象强制转换为正确的类型。

因此,当你在foreach循环中使用var时,你会隐式地match类型定义为object,因为这是枚举器产生的结果。通过显式地match类型定义为Match,你可以指示编译器代表你将每个匹配项强制转换为正确的类型。


1
OP在代码注释中提到了Match match可以解决问题,但是想知道为什么var不能工作。 - Bala R

-1

这不是可读性的问题。对我来说,在枚举MatchCollection时,假设它会产生一个Match是一个安全的假设(而且也很容易阅读)。我感谢这个答案,但当这是一个“为什么”问题时,仅仅说某些东西是不合适的并没有提供太多信息。 - D'Arcy Rittich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接