Covariância vs contravariância com respeito a herança de classe
-
07-07-2019 - |
Pergunta
Qual é o significado dos conceitos 'covariância' e 'contravariance'?
Dado 2 classes, Animal e Elephant (que herda de Animal ), o meu entendimento é que você teria um erros em tempo de execução se você tentar colocar um elefante em uma matriz de animais, e isso acontece porque Elephant é "maior" (mais específico) do animal. Mas você poderia colocar um animal em uma matriz de elefante, vendo como Elephant é garantida para conter as propriedades animal?
Solução
Você tem isso para trás. Você pode adicionar um elefante para uma matriz animal porque é um Animal, e está garantido para ter todos os métodos de um animal é obrigado a ter. Você não pode adicionar um animal para uma matriz do elefante, porque ele faz não tem todos os métodos que um elefante é obrigado a ter.
O artigo da Wikipedia sobre covariância e contravariance tem uma boa explicação para isso:
Dentro do sistema tipo de uma linguagem de programação, um operador de tipos de tipos é covariant se ele preserva a ordenação, =, de tipos, que ordena tipos de mais aqueles específicos para os mais genéricos; é contravariante se inverte essa ordem. Se nenhuma destas situações se aplica, o operador é invariável. Estes termos vêm de teoria das categorias.
Além disso, você disse que tipo de elefante era "maior", e este não é o caso. Tipo de animal é "maior" no sentido de que ele inclui tipos mais específicos, tais como o elefante, girafa, e Leão.
Outras dicas
Tenha um olhar para este panorama de covariância e contravariance em C # 4.0 e ver se isso ajuda:
Você deve tentar ler páginas 45-49 de Introducing .NET 4.0 com Visual Studio 2010 que lida com este exemplo exato. Ele ainda tem algumas boas fotos de elefantes.
O principal ponto de tirar é, para fazer isso
var things = new List<IThing<IContent>> { new ConcreteThing() }
com:
public class ConcreteThing : IThing<ConcreteContent>
{
}
é necessário o "out" na definição de interface, o que permitirá formas mais específicas a ser definido, mas nada lido fora do IThing deve ser garantido para ser o tipo mais geral.
public interface IThing<out T> where T : IContent
{
}
public interface IGoOut<out T>
{
T Func();
}
public interface IComeIn<in T>
{
void Action(T obj);
}
public class GoOutClass<T>:IGoOut<T>
{
public T Func()
{
return default(T);
}
}
public class ComeInClass<T> : IComeIn<T>
{
public void Action(T obj) { }
}
==========================================================
object obj = null;
//Covariance Example [Array + IEnumerable<T> + IEnumerator<T> + IInterface<Out T> + Func<T>]
object[] array = (string[]) obj;
IEnumerable<object> enumerable = (IEnumerable<string>) obj;
IEnumerator<object> enumerator = (IEnumerator<string>)obj;
IGoOut<object> goOut = (GoOutClass<string>)obj;
Func<object> func = (Func<string>)obj;
//Contravariance Example[IInterface<in T>]
IComeIn<string> comeIn = (ComeInClass<object>) obj;