Rafał Czabaj
Rafał Czabaj

Reputation: 740

Casting concrete class to generic interface with interface as generic type results in invalid cast exception

I have searched through several posts on the problem I am facing and I have found most similiar topic here

However, here we have a class as type in generic interface casting, and as I checked class SqlCommand inherits from DbCommand which implements IDbCommand. My example: We have a Processor class which let's say have method Process. Processor contains a property which is an interface of generic type described below.

public class Processor
{
IDbTools<IDbCommand> DbTools {get; set;}

public Processor() {}

public void Process()
{
    DbTools = (IDbTools<IDbCommand>)new Tools();
    DbTools.PrepareAndExecuteQuery();
}
}

public class Tools : IDbTools<SqlCommand>
{
    public void PrepareAndExecuteQuery(SqlCommand command);
}

public interface IDbTools<in TCommand>
    where TCommand: IDbCommand
{
    void PrepareAndExecuteQuery(TCommand command);
}

In this example, we will recieve an InvalidCastException, without compilation error. I don't understand why this is happening if SqlCommand inherits from DbCommand and it implements IDbCommand.

The approach that i made to make it works looks like this:

public class Processor<TCommand>
    where TCommand: IDbCommand, new()
{
IDbTools<TCommand> DbTools {get; set;}

public Processor() {}

public void Process()
{
    DbTools = (IDbTools<TCommand>)new Tools();
    DbTools.PrepareQuery();
}
}

public class Tools : IDbTools<SqlCommand>
{
    void PrepareAndExecuteQuery(SqlCommand command);
}

public interface IDbTools<TCommand>
    where TCommand: IDbCommand
{
    void PrepareAndExecuteQuery(TCommand command);
}

So my question is, why is it happening like that. Of course if we would implement

Tools : IDbTools<IDbCommand>

everything would work, but why it isn't in this scenario..

EDIT: I am attaching sample at ideone.com: Code where is the same code just for copy past purposes into new project. Attached required namespaces.

Also adding the in clause, which isn't fixing the issue.

Upvotes: 2

Views: 1276

Answers (1)

jcharlesworthuk
jcharlesworthuk

Reputation: 1079

You need to declare your IDbTools<> interface with the in keyword

public interface IDbTools<in TCommand>
    where TCommand: IDbCommand
{
    void PrepareAndExecuteQuery(TCommand command);
}

See here about Covariance and Contravariance, Microsoft can explain it a lot better than I can

Upvotes: 1

Related Questions