views:

50

answers:

1

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)

+7  A: 

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.

Ben Voigt
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.
pauldoo
+1 PERFECT answer. Haven't thought of it before.
Robert Koritnik
It's not inconsistent, it's the same behavior as casting, consider: `foreach (SomeClass obj in stuff) ((ISomeInterface)obj).SomeInterfaceMethod();`
Ben Voigt
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.
pauldoo