Reputation: 375
I have a problem with casting generic types.
For example I have classes:
public class Dog
{
}
public class Husky : Dog
{
}
public class MyWrapper<T> where T : class
{
}
and then I want to do something like this, but I don't know how
MyWrapper<Husky> husky = new MyWrapper<Husky>();
List<MyWrapper<Dog>> dogs= new List<MyWrapper<Dog>>();
dogs.Add(husky); // how to cast husky to MyWrapper<Dog>?
EDIT: Changed Animal<T>
to MyWrapper<T>
, so it will be more adequate example
Upvotes: 6
Views: 270
Reputation: 39095
You could use the generic covariance of interfaces in C# 4 or later. In order to do so, you'd need to define a covariant interface (using out
) and have MyWrapper
implement that interface:
public class Dog
{
}
public class Husky : Dog
{
}
public class MyWrapper<T> : IMyWrapper<T> where T : class
{
}
public interface IMyWrapper<out T> where T : class
{
}
Then you can do this:
var husky = new MyWrapper<Husky>();
var dogs = new List<IMyWrapper<Dog>>();
dogs.Add(husky);
Upvotes: 8
Reputation: 64943
You need covariance for that - upcasting a generic type -.
But C# covariance is only supported on:
For that reason, I only find a solution: create a marker interface IAnimal<T>
:
public class Dog
{
}
public class Husky : Dog
{
}
public interface IAnimal<out T>
where T : class
{
}
public class Animal<T> : IAnimal<T> where T : class
{
}
And now this will work:
List<IAnimal<Dog>> list = new List<IAnimal<Dog>>();
list.Add(new Animal<Husky>());
Learn more about covariance and contravariance on MSDN:
Anyway... what's the point of the generic constraint T : class
? You only know that T
is a class, but it could have no public constructor, or it could be a rock instead of a dog, who knows?
Or, what's the point of this class hierarchy? As other have pointed out in their answers, your hierarchy isn't very object-oriented-ish: a Dog IS an animal so Dog
DERIVES Animal
.
Just changing that, you've lost the need of using generic type parameters.
Maybe you prefer composition over inheritance, but I tend to decide what's best with this question:
If I talk about the specialized type, can I say "B is A"? => Then I choose inheritance.
If I talk about the specialized type, can I say "B is part of A" => Then I choose composition.
Actually I believe that covariance solves your question, but I feel it's a wrong use case of this language feature.
Upvotes: 5
Reputation: 1678
Any reason why you would not arrange your class inheritance as follows? I am not sure why Animal needs to accept a type parameter.
public abstract class Animal
{
}
public class Dog : Animal
{
}
public class Husky : Dog
{
}
Upvotes: 6
Reputation: 26446
I'm afraid you can't - although Husky
is a Dog
, Animal<Husky>
is not an Animal<Dog>
.
See .NET Casting Generic List for a similar question.
Upvotes: 7