2016-06-19 23 views
6

Non sono chiaro sul concetto di Covariance in C# quando si tratta di interfacce. Strettamente basato sul mio esempio qui sotto, questo è un esempio di Covariance, per favore descrivi perché o perché no.Covariance con C# e Interfacce

class Program 
{ 
    static void Main() 
    { 
     ICarInterface car = new Car(); 
    } 
} 

interface ICarInterface 
{ 
    void Start(); 
} 

class Car : ICarInterface 
{ 
    public void Start() 
    { 

    } 
} 
+0

No, questo non è. È legato ai generici. Ci sono un sacco di domande su SO già. – nawfal

+0

Non capisco però, perché è strettamente correlato a Generics? Nel mio esempio, Car eredita da ICarInterface. Quindi non è il seguente un upcast implicito che significherebbe che è un esempio di Covariance? Cosa mi manca? ICarInterface car = new Car(); – Exocomp

+0

Questo non è *** un duplicato. Exocomp sta chiedendo se * il codice specifico che mostra * è un esempio di covarianza (e perché/perché no), non per una grande lista di "esempi del mondo reale" di covarianza. Potrebbe * essere un duplicato di una domanda che spiega cos'è la covarianza, ma non è quella scelta. Riapertura ... –

risposta

0

Questo non è un esempio di covarianza, è solo un semplice esempio di polimorfismo. Here puoi trovare le differenze tra covarianza e polimorfismo

+0

Sono andato al link che hai dato che ha degli esempi usando .NET 4 e ad essere sincero non risponde perché il mio esempio non è un esempio di Covariance. – Exocomp

2

No, questa non è veramente covarianza. Questa è solo l'implementazione di un'interfaccia. In particolare, è un esempio di compatibilità di assegnazione . Poiché la classe Car implementa l'interfaccia ICarInterface, un oggetto Car può essere assegnato a una variabile di tipo ICarInterface. Un oggetto di un tipo più specifico (Car) è stato assegnato a un'area di archiviazione per un tipo meno specifico (ICarInterface), che funziona perché i due tipi sono compatibili ai fini dell'assegnazione.

La covarianza è una cosa leggermente diversa. Una relazione di tipo è covariante se conserva l'ordine dei tipi (dal più specifico al più generico). Ad esempio, IEnumerable<T> è covariante rispetto al tipo T, quindi conserva l'ordine dei tipi IEnumerable<Vehicle> (più generico) e IEnumerable<Car> (più specifico). (In questo esempio, assumiamo ovviamente che Car sia una sottoclasse di Vehicle).

Eric Lippert has written an excellent article that distinguishes between covariance and assignment-compatibility. Diventa leggermente tecnico e teorico, ma dovresti assolutamente leggerlo. Non lo farei giustizia cercando di sintetizzarlo ulteriormente qui.


Un esempio di covarianza più comprensibile (almeno secondo me) è la covarianza di tipo ritorno. È qui che l'override di una classe derivata di un metodo di classe base restituisce un tipo più specifico. Per esempio:

abstract class Habitat 
{ 
    public abstract Animal ApexPredator(); 
} 

class Savanna : Habitat 
{ 
    public override Lion ApexPredator() 
    { ... } 
} 

class Ocean : Habitat 
{ 
    public override Shark ApexPredator() 
    { ... } 
} 

In questo esempio, la classe astratta Habitat ha due sottoclassi concrete: Savanna e Ocean. Tutti gli habitat hanno un ApexPredator, che è di tipo Animal. Ma in un oggetto Savanna, il predatore dell'apice è un Lion, mentre in un oggetto Ocean, il predatore dell'apice è un Shark. Questo è legale e sicuro perché Lion e Shark sono entrambi i tipi di Animal s.

Sfortunatamente, C# non supporta la covarianza del tipo di ritorno. È, tuttavia, supportato da C++ (incluso C++/CLI), Java e una serie di altri linguaggi orientati agli oggetti.

Eccone altri concrete examples of covariance.

+0

Ciao Cody, il tuo esempio relativo al C# che non supportava la covarianza del tipo di ritorno mi ha fatto riflettere un po 'e vedo ciò che dici in particolare in quell'esempio. Immagino che tu possa risolvere il problema usando Generics. Usare un segnaposto per il tipo di ritorno, ma comunque non scendere troppo fuori tema. La mia domanda è stata davvero il motivo per cui il mio esempio non era Covariance, tu dici che è un esempio di "Compatibilità di assegnazione" ma non spiega perché non è Covariance? È possibile che "la compatibilità di assegnazione" sia covarianza, ma non tutta la covarianza è "compatibilità di assegnazione"? – Exocomp

+0

@exo Beh no, non si vorrebbe davvero usare i generici come sostituto della covarianza di tipo restituito. I generici non implicherebbero alcuna relazione tra i tipi, quando una relazione è l'intero punto della covarianza di tipo ritorno. Il metodo standard di emulazione della covarianza di tipo restituito in C# è il metodo nascosto. Rendi il metodo override 'protected', quindi aggiungi un metodo' public' che nasconde ('new') il metodo sottoposto a override. Se hai altre domande al riguardo, dovresti fare una nuova domanda. –

+0

@exo Come per le altre tue domande ... * "La mia domanda era davvero il motivo per cui il mio esempio non era Covarianza, tu dici che è un esempio di" Compatibilità di assegnazione "ma non spiega perché non è Covariance?" * Hai leggi il post del blog collegato? Fa un ottimo lavoro di spiegare la differenza tra i due. Quale parte non hai capito? * "È possibile che la" Compatibilità di assegnazione "sia covarianza ma non tutta la covarianza è" compatibilità di assegnazione "?" * No, sono concetti distinti. Si potrebbe dire che la compatibilità dell'assegnazione è preservata in una relazione covariante, però. –

3

La covarianza è correlata all'interazione di sottotipi e generici. Poiché il tuo programma non coinvolge i generici, non è un esempio di covarianza.

Se U è un sottotipo di V (ad esempio U = Pear e V = Fruit), poi un tipo generico G<T> è detto essere covariante in T se G<U> è un sottotipo di G<V>.Ad esempio, IEnumerable<Pear> è un sottotipo di IEnumerable<Fruit>: qualcosa da cui si possono prendere le pere può essere utilizzato per ricavarne i frutti.

Se G inverte la relazione di sottotipo (G<V> è un sottotipo di G<U>), si dice che sia contravariant in T. Per esempio, Action<Fruit> è un sottotipo di Action<Pear>: qualcosa che si può mettere frutta in può essere utilizzato per mettere le pere in

Nel tuo esempio, né ICarInterfaceCar ha un parametro di tipo che potrebbe essere covarianti in

..

In particolare, in C#, un tipo generico è covariante in un parametro di tipo T se T è contrassegnato con out. È controverso in T se T è contrassegnato con in.

+0

>> "La covarianza è correlata all'interazione di sottotitoli e generici" Per quanto riguarda la covarianza dell'array in C# 1, i generici non esistevano, quindi la tua affermazione non è completamente corretta. Per riassumere la tua risposta affermando che per avere Covariance è necessario avere una collezione/lista generica? Quindi, dato che il mio esempio non ha una collezione/lista generica, non ha Covariance? – Exocomp

+1

C# non aveva generici al momento, quindi il caso specifico degli array era hardcoded. Essenzialmente, array * è * un tipo generico: invece di 'T []' potresti leggere 'Array '. (L'attuale classe 'Array' non è generica, questo è un artefatto storico, proprio come il non-generico' IList' e 'ArrayList'.) La covarianza di matrice qui significa che' Pear [] 'è un sottotipo di Fruit [] '. È analogo al caso di "IEnumerable ". (Si noti che la covarianza dell'array è pericolosa, poiché significa che si può mettere un 'Orange' in un' Fruit [] 'che è in realtà un' Pear [] '. Questo è evitato dai controlli di runtime.) – Ruud

+0

Inoltre, covarianza e controvarianza sono non limitato alle collezioni generiche. Ad esempio, 'Func ' è covariante in 'TResult' e controvariante in' T'. Covarianza e controvarianza sono proprietà dei parametri del tipo. Dato che non ci sono parametri di tipo nel tuo esempio, non c'è nulla che * potrebbe * essere covariante. – Ruud