Covarianza vs. contraddizione rispetto all'eredità di classe
-
07-07-2019 - |
Domanda
Qual è il significato dei concetti "covarianza" e "contraddizione"?
Dato 2 classi, animale e elefante (che eredita da animale ), la mia comprensione è che si otterrebbero errori di runtime se provi a mettere un Elefante in una serie di Animali, e questo accade perché l'Elefante è "più grande". (più specifico) rispetto agli animali. Ma potresti collocare un animale in una schiera di elefanti, vedendo come è garantito che l'Elefante contenga le proprietà degli animali?
Soluzione
Lo hai al contrario. Puoi aggiungere un elefante a un array di animali perché è un animale ed è garantito che abbia tutti i metodi che un animale deve avere. Non è possibile aggiungere un animale a un array di elefanti perché non ha tutti i metodi richiesti da un elefante.
L'articolo di Wikipedia su covarianza e contravarianza ha una buona spiegazione di questo:
All'interno del sistema di tipi di un linguaggio di programmazione, un operatore da tipi a tipi è covariante se conserva l'ordinamento, =, di tipi, che ordina tipi da più specifici a più generici; è contraddittorio se inverte questo ordine. Se nessuno dei due si applica, l'operatore è invariante. Questi termini derivano dalla teoria delle categorie.
Inoltre, hai detto che il tipo Elephant era "più grande", e non è così. Il tipo di animale è "più grande" nel senso che include tipi più specifici, come Elefante, Giraffa e Leone.
Altri suggerimenti
Dai un'occhiata a questa panoramica di covarianza e contraddizione in C # 4.0 e vedi se questo aiuta:
Dovresti provare a leggere le pagine 45-49 di Presentazione di .NET 4.0 con Visual Studio 2010 che tratta questo esempio esatto. Ha anche delle belle foto di elefanti.
Il punto principale da eliminare è, per fare questo
var things = new List<IThing<IContent>> { new ConcreteThing() }
con:
public class ConcreteThing : IThing<ConcreteContent>
{
}
hai bisogno di " out " nella definizione dell'interfaccia, che consentirà di impostare moduli più specifici, ma qualsiasi cosa letta da IThing deve essere garantita come il tipo più generale.
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;