2010-02-09 23 views
6

E 'possibile "upcast" da una classe generica basata su T, in una classe generica basata su qualcosa di più generale di T?Upcasting con un parametro di tipo generico

Ad esempio, supponiamo di avere una classe denominata Derived che eredita da una classe denominata Base. Posso mai fare qualcosa di simile:

List<Derived> der = new List<Derived>(); 
List<Base> bas = (List<Base>) der; 

O, utilizzando interfacce, è mai possibile fare qualcosa del genere:

List<MyClonableType> specific = new List<MyClonableType>(); 
List<IClonable> general = (List<IClonable>)specific; 

Come scritto qui, ognuno di questi esempi non riesce con un InvalidCastException. La domanda che stiamo discutendo è se sia effettivamente impossibile, o semplicemente un errore di sintassi che potrebbe essere risolto se sapessimo come.

+0

Java ha '' per questo tipo di costrutto, Sarei sorpreso che C# non abbia un equivalente – Romain

+1

C# ha vincoli generici (la parola chiave where) per la stessa cosa che estende, ma I ' Non è positivo questo è ciò che Auraseer cerca. Vuole effettivamente utilizzare la varianza sulla collezione dal suo aspetto. –

+0

@Romain, il cast non è valido in C#, ma è possibile definire un metodo come "void Process (Elenco in cui T: Base {...}' – finnw

risposta

3

C# 4.0 will have that feature.

Sarà abilitato sulle interfacce e dei delegati che aderiscono a determinate regole. List<T> non sarà supportato, in quanto è una classe concreta. IList<T> inoltre non sarà supportato, poiché i suoi metodi utilizzano T in entrambe le posizioni in e out.

+0

Questo link mi dice anche che questo cast non è consentito prima della 4.0. Questo è esattamente quello che volevo sapere. – Auraseer

+0

Anche in .NET 4.0 non si applica all'elenco . – kvb

+0

Buon punto. La varianza è supportata solo su interfacce e delegati. –

0

C'è una bella estensione LINQ:

der.ToList<Base>(); 
+1

credo che questo metodo crei un'intera nuova collezione. Può essere utile, supponendo che tu abbia Linq, ma non è lo stesso di un cast. – Auraseer

+0

È vero che in questo modo è possibile trattare in modo specifico i tipi IEnumberable , ma non è un cast effettivo come richiesto dalla domanda. In questo caso, il metodo ToList () crea un nuovo elenco di e lo riempie mediante la fusione di ciascun elemento dall'originale. –

+0

Se stai solo leggendo * la lista (che è l'unico caso in cui il cast avrebbe senso) presumibilmente non importa se stai leggendo una copia o l'originale. – finnw

1

Questo

List<Derived> der = new List<Derived>(); 
List<Base> bas = (List<Base>)der; 

non è possibile e non dovrebbe mai essere possibile. Cosa succede qui:

Base b = new Base(); 
bas.Add(b); 

Kaboom! è quello che succede Se quanto sopra fosse legale bas farebbe riferimento a der e der non è possibile aggiungere istanze di Base che è ciò che la Add tenterebbe di fare. (Per concretezza, pensate Base come Animal e Derived come Cat, non si può gettare un List<Cat> ad un List<Animal> perché allora si potrebbe aggiungere un'istanza di Dog alla lista fuso che fallire, perché è davvero un List<Cat>.)

Per ragioni analoghe

List<MyClonableType> specific = new List<MyClonableType>(); 
List<IClonable> general = (List<IClonable>)specific; 

non dovrebbe mai essere possibile.

In C# 4.0 alcuni di questi problemi verranno risolti con la nozione di covariance and contravariance. Ad esempio, in C# 4.0 questo sarà legale:

List<Derived> der = new List<Derived>(); 
IEnumerable<Base> bas = der; 

Questo perché IEnumerable<Base> sputa solo le istanze di Base e poiché tutti Derived s sono Base s questo è bene. Detto in altro modo, IEnumerable<Base> dice "So come lanciare istanze di Base a voi" mentre List<Derived> dice "So come lanciare istanze di Derived a voi."Ma dato che tutti gli Derived s sono Base s, ciò significa che sa anche come eseguire istanze di Base. Pertanto, dovrebbe essere possibile assegnarlo a un'istanza di IEnumerable<Base>. Questo è ciò che è possibile in C# 4.0. è un esempio di covarianza.

devo sottolineare che per i tipi come List<T> che hanno metodi che entrambi mangiano T s e sputare T s non è possibile.

Problemi correlati