Why C# compiler allows this to compile and throws runtime exception when run?
class Program
{
static void Main(string[] args)
{
IEnumerable<Test> list = new List<Test>() { new Test() };
foreach(IDisposable item in list)
{
}
}
}
public class Test
{
}
This does compile with any interface and it doesn't compile if you replace IDisposable with concrete class.
The foreach
loop has an implicit cast in it. It's roughly like this:
using (IEnumerator<Test> iterator = list.GetEnumerator())
{
while (iterator.MoveNext())
{
IDisposable item = (IDisposable) iterator.Current;
// Body of foreach loop here
}
}
Back before generics, that was much handier than having to cast in the source code. Now it's not so important, but it would be odd for it to not compile. Note that the compiler will check that it's at least feasible. If you use foreach (string item in list)
that wouldn't compile, because a Test
can't be a string
- but a Test
can be an IDisposable
, because it could refer to an instance of a subclass of Test
that implements IDisposable
. If you make the Test
class sealed, it will fail to compile even with IDisposable
, too, because then a Test
instance can't implement IDisposable
.
Basically, it will compile if a cast from Test
to the iteration type would compile, and will fail to compile otherwise. But it'll fail at execution time if a normal cast would fail at execution time, too.