Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic object needs a cast even though it implements the required interface

Don't think the title can explain what i'm on about and it's a bit difficult to explain, so i'll let the code do the talking. You can copy+paste this into LINQPad and run it as a C# program, or make the necessary adjustments as a regular c# project in visual studio (e.g.: change calls to Dump() to Console.Writeline() etc.) -

Note that if you uncomment out the line in the doStuff method, it won't compile.

My question is, why do i need the cast when generic2 already implements Iab<TA,TB>? Is this some covariance thing? I'm still on .NET 3.5.

void Main()
{
    doStuff<a,b>();
}

public void doStuff<TA, TB>()
where TA : class, Ia, new()
where TB : class, Ib, new()
{
    Iab<TA, TB> x = null;

    x = new generic1<TA, TB>();
    x.Go().Dump();

    //x = new generic2<TA>(); // <-Cannot implicitly convert type 'UserQuery.generic2<TA>' to 'UserQuery.Iab<TA,TB>'. An explicit conversion exists (are you missing a cast?)
    x = (Iab<TA, TB>) new generic2<TA>();
    x.Go().Dump();
}

public interface Ia
{}

public interface Ib
{}

public class a : Ia
{}

public class b : Ib
{}

public interface Iab<TA,TB>
where TA : class, Ia, new()
where TB : class, Ib, new()
{
    string Go();
}

public class generic1<TA, TB> : Iab<TA,TB>
where TA : class, Ia, new()
where TB : class, Ib, new()
{
    public string Go()
    {
        return "generic Base called";
    }
}

public class generic2<TA> : Iab<TA,b>
where TA : class, Ia, new()
{
public string Go()
    {
        return "generic Sub called";
    }
}
like image 629
Frank Tzanabetis Avatar asked Oct 04 '22 00:10

Frank Tzanabetis


1 Answers

I believe this is because you will always get that error when one or more of the types (in this case, TS) is not known at compile time.

The compiler can't guarantee that doStuff() will be called with compatible types, so it forces you to cast.

To see why the compiler can't do this, try calling doStuff() as follows:

public class X: b {}

...

doStuff<a, X>(); // Compiles ok but:

Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'generic21[Demo.Program+X]' to type 'Iab2[Demo.Program+X,Demo.Program+Y]'.

So it is possible for you to call it with types that will make it crash; the compiler won't silently let you do that.

like image 124
Matthew Watson Avatar answered Oct 23 '22 05:10

Matthew Watson