C#foreachの予期しない動作


8

なぜC#コンパイラはこれをコンパイルして実行時にランタイム例外をスローするのを許可するのですか?

class Program
{
   static void Main(string[] args)
   {
      IEnumerable<Test> list = new List<Test>() { new Test() };

      foreach(IDisposable item in list)
      {

      }
   }
}

public class Test
{

}

これは、任意のインターフェイスでコンパイルされ、IDisposableを具象クラスで置き換えてもコンパイルされません。


4
派生インスタンスが存在する可能性があるので、それはコンパイルさTestない実装をIDisposable。事実上、foreachはすべての要素をインターフェイスにキャストしようとし、失敗すると例外をスローします。書くのと同じ(IDisposable)currentElementです。しかし、具体的なクラスでコンパイルしてはならない理由がわかりません。
HimBromBeere

うまくコンパイルできる私のフィドルによると:dotnetfiddle.net/3Up9nU
HimBromBeere

3
@HimBromBeere:はい、それが問題のポイントです。
Jon Skeet、

を使用して例外にforeach (IDisposable item in list.OfType<IDisposable>())
遭遇し

回答:


16

foreachループはそれで暗黙のキャストを持っています。おおよそ次のようになります。

using (IEnumerator<Test> iterator = list.GetEnumerator())
{
    while (iterator.MoveNext())
    {
        IDisposable item = (IDisposable) iterator.Current;
        // Body of foreach loop here
    }
}

ジェネリックの前に戻ると、ソースコードをキャストするよりもずっと便利でした。今はそれほど重要ではありませんが、コンパイルしないのは奇妙です。コンパイラー、それが少なくとも実行可能であること確認することに注意してください。これを使用foreach (string item in list)すると、コンパイルTestできません。それは、aにすることはできませんが、stringa Test はできます。これIDisposableは、Testその実装のサブクラスのインスタンスを参照する可能性があるためIDisposableです。あなたが作る場合はTestクラスが密封され、それもでコンパイルに失敗しますIDisposable、その後ので、あまりにも、Testインスタンスを実装することはできませんIDisposable

基本的Testに、反復型へのキャストからコンパイルされる場合はコンパイルされ、そうでない場合はコンパイルに失敗します。ただし、通常のキャストも実行時に失敗すると、実行時に失敗します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.