vanilla161
vanilla161

Reputation: 375

Casting generic classes in C#

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

Answers (5)

Eren Ers&#246;nmez
Eren Ers&#246;nmez

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

Mat&#237;as Fidemraizer
Mat&#237;as Fidemraizer

Reputation: 64943

You need covariance for that - upcasting a generic type -.

But C# covariance is only supported on:

  • Delegates.
  • Interfaces.

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:

UPDATE

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

D J
D J

Reputation: 7018

not possible Animal<Husky> is not derived from Animal<Dog>.

Upvotes: 2

Matt
Matt

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

C.Evenhuis
C.Evenhuis

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

Related Questions