In a world where IThis shouldn’t be interchangeable with IThat…


Discovered something unexpected the other day. Not sure why I never saw it before, but I found out that if you are iterating through a generic collection of items where the collection is holding an interface, you can use a completely unrelated interface as your iterator.

Not sure what the heck I just said? Let’s look at some code:

   1: List<IAmAnInterface> stuff = new List<IAmAnInterface>

   2:                                  {

   3:                                      new AClass {AValue = "First"},

   4:                                      new AClass {AValue = "Second"}

   5:                                  };


   7: foreach (IAmAnotherInterface item in stuff)

   8: {

   9:     item.DoSomething();

  10: }

Believe it or not, this code will compile. IAmAnInterface and IAmAnotherInterface have nothing to do with each other, and AClass only implements IAmAnInterface:

   1: interface IAmAnInterface

   2: {

   3:     void DoSomething();


   5:     string AValue { get; set; }

   6: }

   1: interface IAmAnotherInterface

   2: {

   3:     void DoSomething();


   5:     string AValue { get; set; }

   6: }

   1: class AClass : IAmAnInterface 

   2: {

   3:     public void DoSomething()

   4:     {

   5:         Console.WriteLine("From AClass {0}", AValue);

   6:     }


   8:     public string AValue { get; set; }

   9: }

So, it looks like this shouldn’t compile, right? No way that it will work in the real world. But the compiler doesn’t have any idea that the objects in the stuff collection in the first snippet doesn’t implement both interfaces. It apparently has to allow for that possibility, which seems strange, but I bet if you were coming at it from the other perspective and had an object from a class that implemented both interfaces, you might find it strange if this didn’t work.

I’m not sure why this decision was made: it seems like it would cause more harm than good, because you will only find out about the problem at runtime when it fails. Of course, if you have a unit test or two around it all, you’ll find that out pretty quickly. Regardless, now I know that the compiler won’t catch this for me. And now you know too.