Ваш код компилируется и работает, так что это "правильно"? Я думаю, это так!
Однако не очень интересно иметь стек, который содержит только один элемент; это не совсем стек. Давайте подумаем, как сделать действительно ковариантный и контравариантный стек.
interface IPush<in T> { void Push(T item); }
interface IPop<out T> { T Pop(); }
class Stack<T> : IPush<T>, IPop<T>
{
private class Link
{
public T Item { get; private set; }
public Link Next { get; private set; }
public Link(T item, Link next) { this.Item = item; this.Next = next; }
}
private Link head;
public Stack() { this.head = null; }
public void Push(T item)
{
this.head = new Link(item, this.head);
}
public T Pop()
{
if (this.head == null) throw new InvalidOperationException();
T value = this.head.Item;
this.head = this.head.Next;
return value;
}
}
И теперь вы можете использовать стек ковариантно для выталкивания и, наоборот, для толкания:
Stack<Mammal> mammals = new Stack<Mammal>();
IPop<Animal> animals = mammals;
IPush<Giraffe> giraffes = mammals;
IPush<Tiger> tigers = mammals;
giraffes.Push(new Giraffe());
tigers.Push(new Tiger());
System.Console.WriteLine(animals.Pop()); // Tiger
System.Console.WriteLine(animals.Pop()); // Giraffe
Что если я хочу использовать только один экземпляр B из ссылки A?
Ваш вопрос: "что если я хочу использовать Тигра, но у меня есть ссылка на Животное?" Ответ «ты не можешь», потому что Животное не может быть Тигром! Если вы хотите проверить, действительно ли ссылка на Animal является тигром, скажите:
Tiger tiger = myAnimal as Tiger;
if (tiger != null) ...
или
if (myAnimal is Tiger) ...
А если вы хотите преобразовать класс C<B>
в C<A>
?
Это невозможно. Там нет ссылки преобразования там. Единственные ковариантные и контравариантные преобразования ссылок в C # 4 находятся на универсальных интерфейсах и универсальных делегатах , которые построены со ссылочными типами в качестве аргументов типа. Универсальные классы и структуры нельзя использовать ковариантно или контравариантно. Лучшее, что вы можете сделать, это заставить класс реализовать вариант интерфейса .