Reputation: 577
I have a covariant/contravariant issue with generics. Here's a code of what I'm trying to do :
in framework DLL:
namespace framework {
public interface IBase
{
//Some code...
}
public abstract class AOverClass<T> : IBase where T : IBase
{
public AOverClass(T pObject)
{
//Some code
}
//Some code...
}
public class workerClass
{
public Dictionary<Type, Type> ObjDictionary;
public AOverClass<IBase> GetOverObj(IBase initObj){
// Get the over Obj type from a dictionary that was loaded previously
// the dictionary contains KVP of <Type, Type> then using Reflection
// to initialise a new OverObj
Type t = Dictionary[initObj.GetType()];
Type[] _typesParamsConstructor = new Type[1];
_typesParamsConstructor[0] = initObj.GetType();
Object[] _valParamsConstructor = new Object[1];
_valParamsConstructor [0] = initObj;
// BIG ISSUE HERE
return (AOverClass<IBase>)t.GetConstructor(_typesParamsConstructor).Invoke(_valParamsConstructor);
}
}
}
in application that references the framework DLL:
namespace myApp {
public class Param : framework.IBase, myApp.IOtherNeeded
{
//Some code
}
public class OverParam : framework.AOverClass<Param>
{
public OverParam(Param pObject) :base(pObject)
{
//Some code...
}
}
public class App
{
private framework.workerClass _wc;
public void Init()
{
_wc = new framework.workerClass();
_wc.ObjDictionary.Add(typeof(Param), typeof(OverParam));
}
public void Run()
{
_wc.GetOverObj(new Param());
}
}
}
The workerClass throws an Exception that it can't cast OverParam
to AOverClass<IBase>
.
How can I work round this?
Foot note : There are no initialisation issues (i.e. the dictionary), I'm just no writting all the code that is not relevent to the issue.
Upvotes: 0
Views: 72
Reputation: 62002
An instance of OverParam
is an AOverClass<Param>
by definition.
But you are trying to cast that instance of OverParam
to AOverClass<IBase>
. That fails.
Now just because any
Param
"is"IBase
can we or can we not conclude that every
AOverClass<Param>
"is"AOverClass<IBase>
?
The answer is: That works precisely if AOverClass<T>
is covariant in T
. The only types that can be covariant (marked with out
before the type parameter T
) in the current version of C# and .NET, are interface types and delegate types. But AOverClass<T>
is a class type.
Also, when we look at your class:
public abstract class AOverClass<T> : IBase where T : IBase
{
public AOverClass(T pObject) // an "in" parameter of type T here! :-(
{
//Some code
}
//Some code...
}
we see that you use T
contravariantly. So even if the language allowed class types to be covariant, it wouldn't apply in your case. This indicates that there is something fundamentally wrong with your assumptions.
Upvotes: 2