Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# compiler fails to recognize a class is implementing an interface

The following code fails to compile (using VS2010) and I don't see why. The compiler should be able to infer that List<TestClass> is 'compatible' (sorry for lack of a better word) with IEnumerable<ITest>, but somehow it doesn't. What am I missing here?


interface ITest {
    void Test();
}


class TestClass : ITest {
    public void Test() {
    }
}

class Program {
    static void Test(IEnumerable<ITest> tests) {
        foreach(var t in tests) {
            Console.WriteLine(t);
        }
    }
    static void Main(string[] args) {
        var lst = new List<TestClass>();

        Test(lst); // fails, why?

        Test(lst.Select(t=>t as ITest)); //success

        Test(lst.ToArray()); // success
    }
}

The compiler gives two errors:

  1. The best overloaded method match for 'ConsoleApplication1.Program.Test(System.Collections.Generic.IEnumerable<ConsoleApplication2.ITest>)' has some invalid arguments

  2. Argument 1: cannot convert from 'System.Collections.Generic.List<ConsoleApplication2.TestClass>' to 'System.Collections.Generic.IEnumerable<ConsoleApplication2.ITest>'

like image 981
Freek Avatar asked May 20 '10 08:05

Freek


3 Answers

What you are trying to do is called covariance - converting from a narrower type (TestClass) to a wider type (ITest). It's something you'll be used to all the time, it happens when you convert from a float to a double for example.

Unfortunately .Net 3.5 and lower does not support covariance in generic classes.

.Net 4.0 now does support covariance (and contravariance) in generics, provided those generic classes are compiled with the keywords out for covariant types and in for contravarient types. IEnumerable in .Net 4.0 is defined as covariant. If you right click on the IEnumerable type and click "goto definition", you'll see this:

public interface IEnumerable<out T> : IEnumerable

If you are using VS2010, you will need to make sure your project is targeting .net 4.0. This can be changed from the project properties. Right click on the project, select properties, goto the "Application" tab and check that the "Target framework" is to to .Net 4.

MSDN has more information.

like image 116
Simon P Stevens Avatar answered Oct 13 '22 01:10

Simon P Stevens


This has to do with variance (covariance and contravariance); check out this post and the answer by Jon Skeet

like image 37
Thomas Avatar answered Oct 13 '22 00:10

Thomas


Check the Target Version of the framework for your project. This code will only work in .NET 4 .

like image 42
Joel Cunningham Avatar answered Oct 13 '22 01:10

Joel Cunningham