C #: É variância (Covariance / Contravariance) uma outra palavra para Polimorfismo?
-
21-08-2019 - |
Pergunta
Eu estou tentando descobrir o significado exato da Covariance
palavras e Contravariance
de vários artigos on-line e perguntas sobre StackOverflow, e pelo que posso entender, é só uma outra palavra para o polimorfismo .
Am I corrigir com a declaração acima? Ou ter eu entendi errado?
Solução
É certamente relacionada com polimorfismo. Eu não diria que eles são apenas "mais uma palavra" para o polimorfismo embora -. Eles são sobre situações muito específicas, onde você pode tratar um tipo como se fosse um outro tipo em um determinado contexto
Por exemplo, com o polimorfismo normal, você pode tratar qualquer referência a um Banana
como uma referência a uma Fruit
- mas isso não significa que você pode substituir Fruit
todas vez que você vê o tipo Banana
. Por exemplo, um List<Banana>
não pode ser tratado como um List<Fruit>
porque list.Add(new Apple())
é válido para List<Fruit>
mas não para List<Banana>
.
covariância permite uma "maior" (menos especica) Tipo de ser substituído em uma API onde o tipo original é única utilizado numa posição "saída" (por exemplo, como um valor de retorno). Contravariância permite um (mais específico) tipo "menor" a ser substituído em uma API onde o tipo original é única utilizado numa posição "de entrada".
É difícil entrar em todos os detalhes em um único post SO (embora esperemos que alguém vai fazer um trabalho melhor do que isso!). Eric Lippert tem um excelente href="https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/" de posts sobre isso.
Outras dicas
Obrigado por todas as shout-saídas, pessoal.
respostasde Jon e Rasmus são bons, gostaria apenas de acrescentar uma nota técnica rápida.
Ao falar casualmente e informalmente, sim, as pessoas usam "covariância" e "contravariance" para se referir a um tipo específico de polimorfismo. Ou seja, o tipo de polimorfismo, onde você tratar uma seqüência de aranhas como se fosse uma seqüência de animais.
Se fôssemos para obter todos os computadores-sciency e tentar fazer definições mais técnicas, então eu provavelmente não diria que covariância e contravariance são "um tipo de polimorfismo". Gostaria de abordar uma definição mais técnica como esta:
Em primeiro lugar, eu notar que existem dois tipos possíveis de polimorfismo em C # que você pode estar falando, e é importante não confundi-los.
O primeiro tipo é tradicionalmente chamado de "polimorfismo ad hoc", e isso é o polimorfismo onde você tem um método M (Animal X), e você passar aranhas e girafas e wallabies a ele, e o método uniformemente trata seu passado-in argumentos da mesma forma, utilizando os pontos comuns garantidos pela classe base animal.
O segundo tipo é tradicionalmente chamado de "polimorfismo paramétrico", ou "polimorfismo genérico". Essa é a capacidade de fazer um método M<T>(T t)
genérica e, em seguida, ter um monte de código no método que mais uma vez, trata o argumento uniformemente com base em semelhanças garantidos pelos constrangimentos ao T.
Eu acho que você está falando sobre o primeiro tipo de polimorfismo. Mas meu ponto é apenas que podemos definir polimorfismo como a capacidade de uma linguagem de programação para coisas diferentes tratar uniformemente com base em uma comunalidade conhecido. (Por exemplo, um tipo de base conhecida, ou conhecida interface implementada.)
Covariância e contravariance é a capacidade de uma linguagem de programação para aproveitam comuns entre tipos genéricos deduzidas comuns conhecidas de seus argumentos de tipo.
Você pode pensar em co- e contravariance como sendo uma forma avançada de polimorfismo. Não apenas você pode usar uma classe criança como se fosse seu pai-classe, com co- e contravariance, o polimorfismo se estende a classes que diz respeito às classes polimórficas.
Imagine duas classes:
public class Pet { /*...*/ }
public class Cat:Pet { /*...*/ }
O polimorfismo é ser capaz de usar um Cat
como um Pet
:
void Feed(Pet pet) { /* ... */ }
Cat cat = ...
Feed(cat);
Co e contravariance é usado para falar sobre a possibilidade de usar um ICollection<Cat>
como um ICollection<Pet>
(covariância):
void FeedAll(ICollection<Pet> pets) { /* ... */ }
List<Cat> cats = ...
FeedAll(cats);
ou usar um Action<Pet>
como um Action<Cat>
(contravariance):
Action<Pet> GetFeeder() { /* ... */ }
Action<Cat> feeder = GetFeeder();
Eric Lippert escreveu uma grande série de posts sobre isso quando eles foram os primeiros projetar o recurso. uma parte é aqui .
Eu encontrei esta coleção:
covariância e Contravariance em C #, Parte Um
covariância e Contravariance em C #, Parte dois: array Covariance
covariância e Contravariance em C #, Parte Três: Grupo Membro Conversão Variance
covariância e Contravariance em C #, Parte IV: Bens Delegado Variance
covariância e Contravariance Em C #, Parte V: funções de ordem superior ferir meu cérebro
covariância e Contravariance em C #, Parte VI: interface de variância
covariância e Contravariance em C # Parte Sete: por que precisamos de uma sintaxe At All
covariância e Contravariance em C #, Parte Oito: opções de sintaxe
covariância e Contravariance em C #, Parte Nove: Breaking Alterações
covariância e Contravariance em C #, Parte Ten: Lidando com a ambiguidade
covariância e Contravariance, Parte Onze: Ao infinito, mas não além
Eu acho que é é tipo especial de polimorfismo não outra palavra para isso. É o polimorfismo em delegados , onde um delegado com um tipo de retorno de base pode aceitar tipo de criança.