Why does foreach skip compile time type checking on interface types?
Asked Answered
R

1

6

When I use a foreach loop in C#, it appears that no compile time type checking is performed if the item type is an interface type.

E.g.

class SomeClass {}
interface SomeInterface {}

IEnumerable<SomeClass> stuff;
foreach(SomeInterface obj in stuff) { // This compiles - why!?
}

This will happily compile and cause an exception at runtime, when it is clear at compile time this makes no sense. If I change the item type from SomeInterface to another class, then compile time type-checking is restored:

IEnumerable<SomeClass> stuff;
foreach(Random obj in stuff) { // This doesn't compile - good!
}

Why is there no compile time type checks when the item type is an interface?

(This occurs with .NET 3.5 SP1 in Visual Studio 2008)

Ramonitaramos answered 2/8, 2010 at 15:42 Comment(1)
Yeah, I've wondered about (and been bitten by) the same thing. Looking forward to the answers from those in the know!Johnette
C
8

It is NOT clear at compile time whether another part of the program, maybe in a different project, has:

class SomeOtherClass : SomeClass, ISomeInterface
{
   public static IEnumerable<SomeClass> GetSomeStuff()
   {
      for( int i = 0; i<10; ++i)
         yield return new SomeOtherClass(i);
   }
}

Now the runtime check SUCCEEDS.

If you mark SomeClass as sealed then this isn't possible, and it's again possible to know at compile time that the cast will never work.

Chigetai answered 2/8, 2010 at 15:46 Comment(4)
What you say is correct. I am surprised that C# takes this approach with "foreach" as it makes the language inconsistent. Method calls don't have this same behaviour for example.Ramonitaramos
It's not inconsistent, it's the same behavior as casting, consider: foreach (SomeClass obj in stuff) ((ISomeInterface)obj).SomeInterfaceMethod();Chigetai
It's just suprising (to me) that foreach is effectively doing a hidden dynamic cast. Other things like variable assignments ("a = b;") or function calls ("myFunc(c);") don't silently perform dynamic casts. Dynamic casts (IMHO) should be clear and obvious in the code.Ramonitaramos
Another reason I should properly seal my classes.Maltha

© 2022 - 2024 — McMap. All rights reserved.