MatchCollection・GroupCollection・CaptureCollectionの各コレクションは、当初非ジェネリックなIEnumerableインターフェイスのみを実装する型指定されていないコレクションとして登場し、その後.NET Standard 2.1/.NET Core 2.0にてIEnumerable<T>/ICollection<T>/IList<T>を実装するようになり、型指定されたコレクションとして扱うことができるようになっています。
一方、Match/Group/CaptureCollectionのGetEnumeratorメソッドは、おそらくAPI互換性維持の観点から、IEnumerable<T>の実装以降も非ジェネリックなIEnumeratorを返す実装のままとなっています。 このためC#では、これらのコレクションクラスから取得した列挙子IEnumeratorで列挙する場合、var
による暗黙的な型指定を行うとobject
として列挙されます。
したがって、これらのコレクションをforeachで列挙を行う際には、明示的に型指定する、IEnumerable<Match>等にキャストしてから列挙する、LINQのOfType<Match>()メソッド・Cast<Match>()メソッドを用いて型変換してから列挙する、などする必要があります。
Match/Group/CaptureCollectionから直接ではなく、ジェネリックインターフェイスを介してGetEnumeratorメソッドを呼び出す場合は、ジェネリックな(型指定された)列挙子IEnumerator<T>を取得できます。 そのため、これらのコレクションを引数としてとる場合は、Match/Group/CaptureCollectionの代わりにIEnumerable/IReadOnlyCollection/IReadOnlyList<Match/Group/Capture>などで受けるようにすることもできます。
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
class Sample {
// MatchCollection直接ではなくIReadOnlyList<Match>として引き受ける
static void PrintMatches(IReadOnlyList<Match> matches)
{
// IReadOnlyList<Match>を介して列挙することで、型指定されたIEnumerator<Match>によって列挙することができる
foreach (var match in matches) {
Console.WriteLine(match.Value);
PrintGroups(match.Groups);
}
}
// GroupCollectionの場合もMatchCollectionと同様
static void PrintGroups(IReadOnlyList<Group> groups)
{
foreach (var group in groups) {
Console.WriteLine(group.Value);
PrintCaptures(group.Captures);
}
}
// CaptureCollectionの場合もMatchCollectionと同様
static void PrintCaptures(IReadOnlyList<Capture> captures)
{
foreach (var capture in captures) {
Console.WriteLine(capture.Value);
}
}
static void Main()
{
PrintMatches(Regex.Matches("text", "pattern"));
}
}
IEnumerable・IEnumeratorインターフェイスと列挙について詳しくはIEnumerable・IEnumeratorを参照してください。