Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot convert source type to target type compilation error

I have this simple class

public class Program
{
    private static void Main(string[] args)
    { 
        ClassB<ClassA> objA = new ClassB<ClassA>();

        ClassB<ITestA<MyDTO>> objB = new ClassB<ClassA>();

    }
}


public class ClassB<T>
{
    ///some code here
}


public interface ITestA<T>
{
    ///some code here
}

public class MyDTO
{
    ///some code here
}

public class ClassA : ITestA<MyDTO>
{
    ///some code 
}

This line of code

ClassB<ITestA<MyDTO>> objB = new ClassB<ClassA>();

is giving compilation error

Cannot implicitly convert type 'ClassB<ClassA>' to 'ClassB<ITestA<MyDTO>> 

Since ClassA implements ITestA, I don't know why would this give a compilation error. Please help me understand what am I doing wrong.

Thanks, Esen

like image 208
Esen Avatar asked Jun 30 '15 21:06

Esen


1 Answers

It's due to a rather complex feature of generics called variance.

Classes are invariant, which means that if you declare ClassB<T>, then when creating an instance:

ClassB<T1> obj = new ClassB<T2>

Then T1 has to be exactly the same class as T2.

You can use interfaces to get around this, eg change your code to the following and it'll compile:

...
public class Program
{
    private static void Main(string[] args)
    {
        ClassB<ClassA> objA = new ClassB<ClassA>();

        IClassB<ITestA<MyDTO>> objB = new ClassB<ClassA>();

    }
}


public interface IClassB<out T>  // <- note the out before T
{
    //some code here
}
public class ClassB<T> : IClassB<T>
{
    //some code here
}
...

In this case, IClassB is declared as covariant, which means that it can handle being given a derived class of T, rather than needing T itself. There are risks around using covariance (and contravariance) though, which is why generic classes are invariant by default.

like image 105
David Arno Avatar answered Sep 29 '22 06:09

David Arno