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

Uncategorized

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:                                  };

   6:  

   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();

   4:  

   5:     string AValue { get; set; }

   6: }

   1: interface IAmAnotherInterface

   2: {

   3:     void DoSomething();

   4:  

   5:     string AValue { get; set; }

   6: }

   1: class AClass : IAmAnInterface 

   2: {

   3:     public void DoSomething()

   4:     {

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

   6:     }

   7:  

   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.

Advertisements

One thought on “In a world where IThis shouldn’t be interchangeable with IThat…

  1. This is because foreach does an implicit cast for you. If you look at the MSIL for your code you will notice a “castclass”. The castclass call does not actually cast an object until after it comes off the stack. Hence the runtime. AFAIK this was like this before generics was introduced to .NET. When they introduced generics, if they changed the internals of the foreach, it would break backwards compatibility. So, they introduced the keyword ‘var’ for this exact reason (among many others). “var” will strongly type your object at compile time and give you the expected results. As such this code could be written as above with one minor alteration in order to get the expected compile time error:

    foreach (var item in stuff)
    {
    item.DoSomething();
    }

Comments are closed.