Today’s C# quiz – does this compile?


using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<Inter1> ienum1 = new Class1[] { new Class1() };
        foreach (Class2 c in ienum1)
        {
            Console.WriteLine(c);
        }
    }
}

public interface Inter1 { }
public class Class1 : Inter1 { }
public class Class2 { }

Comments (12)

  1. jibey.jacob says:

    No, it won’t compile.

    Class2 has no relation to Class1 or Inter1. c has to be either of type Class1 or Inter1 for this to compile.

  2. jibey.jacob says:

    Why is this question so simple? I was expecting questions that only C# MVPs can solve.

  3. MSDN Archive says:

    # csc temp.cs

    Microsoft (R) Visual C# 2008 Compiler version 3.5.20921

    for Microsoft (R) .NET Framework version 3.5

    Copyright (C) Microsoft Corporation. All rights reserved.

    # temp

    Unhandled Exception: System.InvalidCastException: Unable to cast object of type ‘Class1’ to type ‘Class2’.

      at Program.Main(String[] args)

    Bonus question – why does it compile?

  4. hboyceiii says:

    It’s an interesting scenario…same thing happens in VS2k5.  My take on what’s happening is IEnumerable<> : IEnumerable (non-generic).  the foreach macro is expanded to:

    IEnumerator e = ienuml.GetEnumerator();

    while(e.MoveNext())

    {

    Class2 current = e.Current as Class2;

    //code in foreach

    }

    since IEnumerator isn’t strongly-typed, the cast to class 2 is what’s causing the exception.

    And I didn’t cheat (ILDasm or Reflector) either!!! 😉

  5. hboyceiii says:

    As an addendum to that, the Class1[] is really an instance of System.Array – not generic – implements IEnumerable; however, it’s legit to cast to/from IEnumerable and IEnumerable<>.

    Since you’re casting from non-generic to generic, I guess the compiler can’t resolve the types…and that’s why it breaks…

    [this time I did cheat and use ILDasm ;-)]

  6. using System; using System.Collections.Generic; class Program { static void Main( string [] args) { IEnumerable&lt;Inter1&gt;

  7. MSDN Archive says:

    Good comments so far.  A couple more hints/tips:

    – Foo[] (array of Foo) *does* implement IEnumerable[Foo] (the generic interface)

    – the code would fail to compile if IEnum1 was IEnumerable[Class1] instead of IEnumerable[Inter1]

     – for those that think that it’s just the IEnumerable (non-generic) implementation that gets this to work

  8. kdbond says:

    It compiles because the foreach generates an iterator over types of the interface Inter1 and since the Interface is empty the signature of Class2 matches the interface even though it does not actually implement it.

  9. MSDN Archive says:

    Good try, but even if you add something to the interface and don’t add it to Class2, the code still compiles – you can change the last 3 lines, for instance, to this and it still compiles.

    public interface Inter1 { int MyProperty { get; } }

    public class Class1 : Inter1 { public int MyProperty { get { return 0; } } }

    public class Class2 { }

  10.        foreach (Class2 c in ienum1)

           {

               Console.WriteLine(c);

           }

    is equivalent to in this case to:

    IEnumerator<Iter1> e = null;

    try

    {

     e = ienum1.GetEnumerator();

     while(e.MoveNext())

     {

       Class2 instance =  (Class2) e.Current;

       Console.WriteLine(instance);

     }

    }

    finally

    {

     e.Dispose();

    }

    foreach includes an explicit cast.

  11. Got a few good comments to the quiz post , but nobody that commented got it right. I went ahead and sent

  12. Got a few good comments to the quiz post , but nobody that commented got it right. I went ahead and sent