質問: Regex.Matches(text, @"\d"); foreach(var match in matches) { Console.WriteLine(item.Value); // error! } ``` 以下のようにMatch型と明示してやれば問題ないのですが、 何故varによるデフォルト?がObject型が返ってきているのかがわかりません。 ``` foreach(Match match in matches) ``` 例えばList型はforeachで要素にvarを指定してもvarはSystem.String型と認識されます。 この違いはなんでしょうか?
回答: `foreach`の動作はドキュメントに書かれていますが、実は `IEnumerable` や `IEnumerable` を取り出すわけではありません。 > > * 戻り値の型がクラス、構造体、インターフェイス型のいずれかである、パラメーターなしのパブリック メソッド GetEnumerator がある型。 C# 9.0 以降では、GetEnumerator メソッドを型の拡張メソッドにすることができます。 > * GetEnumerator メソッドの戻り値の型に、パブリック プロパティ Current と、戻り値の型が Boolean であるパラメーターなしのパブリック メソッド MoveNext がある。 > > > 要するに、`foreach`ループは`GetEnumerator().Current`を扱います。その上で、`MatchCollection`はジェネリックが登場する前の.NET 1時代から続く代物で、`MatchCollection.GetEnumerator().Current`は`object`と定義されています。対して、`List.GetEnumerator().Current`は`T`になるように定義されています。 ちなみに F# の `for ... in` 構文は `get_Item()` メソッドの戻り値を見る仕様なので、 `MatchCollection` に対しても `Match` が得られることを推論できてしまいます。 なぜ`get_Item()`なのかというと`Item`インデクサプロパティの実体メソッドがこの名前を使うことが多いからです。たまに別のメソッド名が使われているクラスに対しては推論できずに`object`とされてしまうこともあります。 > > 、MatchCollectionをみると `ICollection`, `IEnumerable,...` といったものを継承しており > > > 蛇足ですが、`MatchCollection`がこれらのインターフェースを実装するのは.NET Standard 2.1以降および.NET Core 2.0以降です。それ以外、例えば.NET Framework 4.8では実装していません。 `foreach`は前述の通り使えませんが、LINQは使えるようになるということです。