71433


タイトルの通りですが、例えば以下のように、  
C#のMatchCollectionをforeachで処理しようとしたときに  
varがIDEで見るとSystem.Object型と認識されます。

結果、ループの内部でMatch型と想定した処理がエラーとなります。

[code]

    var text = "1234abcd5678"
    var matches = Regex.Matches(text, @"\d");  
    foreach(var match in matches)
    {
        Console.WriteLine(item.Value);　// error!
    }
    
[/code]

以下のようにMatch型と明示してやれば問題ないのですが、  
何故varによるデフォルト？がObject型が返ってきているのかがわかりません。

[code]

    foreach(Match match in matches)
    
[/code]

例えばList型はforeachで要素にvarを指定してもvarはSystem.String型と認識されます。  
この違いはなんでしょうか？


CC BY-SA 4.0
2020-10-22T13:10:39.473
71430
2020-10-24T15:06:01.670
2020-10-22T15:24:12.867
4236
42136
question
c#
C#のMatchCollectionをforeachで回したときvarを使用した型がMatchでなくobjectなのはなぜでしょうか


[`foreach`の動作](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-
reference/keywords/foreach-in)はドキュメントに書かれていますが、実は `IEnumerable<T>` や
`IEnumerable` を取り出すわけではありません。

>   * 戻り値の型がクラス、構造体、インターフェイス型のいずれかである、パラメーターなしのパブリック メソッド GetEnumerator がある型。
> C# 9.0 以降では、GetEnumerator メソッドを型の拡張メソッドにすることができます。
>   * GetEnumerator メソッドの戻り値の型に、パブリック プロパティ Current と、戻り値の型が Boolean
> であるパラメーターなしのパブリック メソッド MoveNext がある。
>

要するに、`foreach`ループは`GetEnumerator().Current`を扱います。その上で、`MatchCollection`はジェネリックが登場する前の.NET
1時代から続く代物で、[`MatchCollection.GetEnumerator().Current`](https://docs.microsoft.com/en-
us/dotnet/api/system.text.regularexpressions.matchcollection.getenumerator?view=netcore-3.1)は`object`と定義されています。対して、[`List<T>.GetEnumerator().Current`](https://docs.microsoft.com/en-
us/dotnet/api/system.collections.generic.list-1.getenumerator?view=netcore-3.1)は`T`になるように定義されています。

* * *

ちなみに F# の `for ... in` 構文は `get_Item()` メソッドの戻り値を見る仕様なので、 `MatchCollection`
に対しても `Match` が得られることを推論できてしまいます。  
なぜ`get_Item()`なのかというと`Item`インデクサプロパティの実体メソッドがこの名前を使うことが多いからです。たまに別のメソッド名が使われているクラスに対しては推論できずに`object`とされてしまうこともあります。

* * *

> 、MatchCollectionをみると `ICollection<Match>`, `IEnumerable<Match>,...`
> といったものを継承しており

蛇足ですが、`MatchCollection`がこれらのインターフェースを実装するのは.NET Standard 2.1以降および.NET Core
2.0以降です。それ以外、例えば.NET Framework 4.8では実装していません。  
`foreach`は前述の通り使えませんが、LINQは使えるようになるということです。


CC BY-SA 4.0
2020-10-22T15:08:47.370
71433
2020-10-24T15:06:01.670
2020-10-24T15:06:01.670
4236
4236
71430
answer