I've inherited an application consisting of a basic framework of which I have no control over. Now some classes have changed there and I have to update our usage of it.
The basic framework is relying heavily on generics. Now I have a certain problem when using them. This code represents the problem in a simplified way:
class MainClass<T, U, V>
where T : ClassA<U, V> , new()
where U : ClassB<V>, new()
where V : ClassC
{
void AddSomething()
{
U myU = new U();
myU.Data = new ClassCImpl();
// "Cannot convert source type ClassCImpl to target type V"
}
void AddSomething2()
{
List<U> val = new List<U>();
ClassB<ClassC> myClBC = new ClassB<ClassC>();
myClBC.Data = new ClassCImpl();
val.Add(myClBC);
// "Argument type ClassB<ClassC> is not assignable to U"
}
}
The framework classes look like this:
class ClassA<T, U>
where T : ClassB<U>
where U : ClassC
{ }
class ClassB<T> where T : ClassC
{
public virtual T Data {get; set;}
}
abstract class ClassC { }
class ClassCImpl : ClassC { }
The code is currently used as in the Method AddSomething
in class MainClass
. This code throws the error "Cannot convert source type ClassEImpl to target type V". I thought that this might be related to ClassCImpl
being not the exact type as in the generic constraint of type ClassC
. So I tried to use AddSomething2
, as I don't need it necessarily generic there. But, this throws the error "Argument type ClassB is not assignable to U", but I thought ClassB<ClassC>
is exactly what U
is.
Now I am wondering, where is the error in my logic?
You're assuming that ClassCImpl
is compatible with the T
of your ClassB<T>
.
Suppose I have:
public class OtherClassC : ClassC {}
...
MainClass mc = new MainClass<ClassB<OtherClassC>, OtherClassC>();
mc.AddSomething();
That's going to try to set a ClassCImpl
value to a property of type OtherClassC
. That's not going to work.
Likewise your AddSomething2
method would try to add a ClassB<ClassC>
to a List<ClassB<OtherClassC>>
- again, that's not valid.
It's not entirely clear what you're trying to achieve, but when you start trying to use specific concrete types within your AddSomething
methods, you're likely to have problems. You should possibly try making some of this code less generic - aside from anything else, that would make it simpler to work out what's wrong.
See more on this question at Stackoverflow