2012-09-19 13 views
17

Io sono l'attuazione IListSource che richiede un metodo GetList() con la seguente firma:convertire da IList <T> a non generica IList

IList GetList() 

Sto usando .NET Framework 2 e sto volendo restituire un oggetto che implementa IList come segue:

public System.Collections.IList GetList() 
{ 
    return this._mydata; // Implements IList<MyDataRow>    
} 

Ma ottengo un errore di compilazione dicendo: Cannot implicitly convert type MyData to System.Collections.IList.

Se creo un elenco nuovo di tipo List<MyDataRow>, lo compilo e restituisco questo oggetto elenco, quindi funziona. Quindi, in altre parole, questo funziona:

public System.Collections.IList GetList() 
{ 
    List<MyDataRow> list = new List<MyDataRow>(); 
    foreach (MyDataRow row in this._mydata) 
    { 
     list.Add(row); 
    } 
    return list; 
} 

Ma sembra molto inefficiente di dover ricreare la lista solo per ottenere da tipo IList<T>-IList. Perché posso restituire un List<MyDataRow>' from 'GetList(), ma non uno IList<MyDataRow>? Qualcuno sa di un modo per me di restituire il IList<MyDataRow> senza ripopolare un nuovo elenco?

UPDATE:

La variabile _mydata membro è dichiarato:

private MyData _mydata; 

E MyData viene dichiarata:

public class MyData : IList<MyDataRow> 
{ 
    .... 
} 
+0

Qual è il tipo dichiarato della _mydata' campo ' ? –

+1

@NicoleCalinoiu: Secondo il messaggio di errore che ottiene, è 'MyData'. – Heinzi

risposta

14

Perché è che io posso restituire un List<MyDataRow> da GetList(), ma non uno IList<MyDataRow>

Questo perché List<T> implementa IList, IList<T> non può essere gettato a IList sono 2 interfacce separate. Quindi, per rispondere alla tua domanda:

Qualcuno sa di un modo per me di restituire il IList<MyDataRow> senza ripopolare una nuova lista?

Se il tipo concreto implementa IList (che List<T> fa), allora si può lanciare in modo esplicito per esempio

return (IList)this.mydata; 

Aggiornamento

Sulla base della sua aggiornamento, sarà necessario aggiornare MyData per implementare IList altrimenti non hai scelta, ma per restituire una nuova collezione che fa attuarla.

In alternativa, se MyData è davvero un elenco generico poi vorrei suggerire lo avete ereditare da List<T>, in questo modo si ottiene molto di più compatibilità flessibilità & fuori dalla scatola per esempio

class MyData : List<MyDataRow> 
{ 
} 
+0

Questo spiega il problema, ma non fornisce una soluzione: myData è di tipo IList , avrebbe ancora bisogno di chiamare .ToList() e vuole evitarlo. –

+0

@Baboon se 'myData' è di tipo' IList ', ma il tipo concreto è' Lista 'quindi un cast esplicito è tutto ciò che è necessario. – James

+1

Grazie, James, per la tua risposta dettagliata. Ti darò credito perché il suggerimento di ereditare dalla lista , piuttosto che incapsulare un membro della lista nella mia classe come stavo facendo, era davvero la soluzione più semplice al mio problema. Grazie per l'aiuto. – BruceHill

4

La classe MyData necessità di attuare il IList insieme con la versione generica IList<T>.

class MyData : IList<MyDataRow>, IList 
{ 
} 
+0

+1. Mi sono permesso di fissare il nome della classe. (Secondo il messaggio di errore dell'OP, la classe stessa è MyData, non MyDataRow). – Heinzi

+0

Grazie, quindi funziona anche :) – Xharze

2

Se fosse possibile convertire un IList<T> in un IList direttamente, si potrebbe restituire un elenco che potrebbe (per esempio) essere "contaminato" con T oggetti non attraverso il suo metodo Add(object).

+0

Il tuo secondo paragrafo arriva al punto cruciale, ma il primo sembra un po 'fuori - l'errore di compilazione avviene proprio perché 'IList ' è * non * derivato da 'IList'. – shambulator

+0

Punto eccellente. Modificato di conseguenza, e grazie per la correzione. Hai assolutamente ragione. –

3

IList<T> non si estende IList, perché non è ragionevole aspettarsi che ogni implementazione della versione generica offra lo stesso contratto di quella non generica. Se si estendesse IList, qualcuno potrebbe prendere il valore restituito da GetList e ragionevolmente aspettarsi di chiamare, ad es. Add(DateTime.Now) o Add(Thread.CurrentThread). Questo è ciò che promette IList.

Questo è il motivo per copiare il vostro elenco a un List<T> opere - List<T> implementa entrambe interfacce e getta quando il suo (esplicitamente implementato) IList metodi vengono chiamati con tipi di parametri inadeguati.

Se riesci a farla franca restituendo IEnumerable, fallo invece. Se è possibile restituire IList<MyDataRow>, quindi farlo. Se si ha realmente bisogno di un ritorno non generico IList, quindi implementare l'interfaccia e gestire i valori non MyDataRow in modo appropriato.

+0

+1 per indicare i pericoli dell'implementazione di 'IList' insieme a' IList ' –

3

O implementare IList sulla tua classe raccolta di dati o di creare un adattatore, che avvolge IList<T> e implementa IList:

public sealed class NonGenericList<T> : IList 
{ 
    private readonly IList<T> _wrappedList; 

    public NonGenericList(IList<T> wrappedList) 
    { 
     if(wrappedList == null) throw new ArgumentNullException("wrappedList"); 

     _wrappedList = wrappedList; 
    } 

    public int Add(object value) 
    { 
     _wrappedList.Add((T)value); 
     return _wrappedList.Count - 1; 
    } 

    public void Clear() 
    { 
     _wrappedList.Clear(); 
    } 

    public bool Contains(object value) 
    { 
     return _wrappedList.Contains((T)value); 
    } 

    public int IndexOf(object value) 
    { 
     return _wrappedList.IndexOf((T)value); 
    } 

    public void Insert(int index, object value) 
    { 
     _wrappedList.Insert(index, (T)value); 
    } 

    public bool IsFixedSize 
    { 
     get { return false; } 
    } 

    public bool IsReadOnly 
    { 
     get { return _wrappedList.IsReadOnly; } 
    } 

    public void Remove(object value) 
    { 
     _wrappedList.Remove((T)value); 
    } 

    public void RemoveAt(int index) 
    { 
     _wrappedList.RemoveAt(index); 
    } 

    public object this[int index] 
    { 
     get { return _wrappedList[index]; } 
     set { _wrappedList[index] = (T)value; } 
    } 

    public void CopyTo(Array array, int index) 
    { 
     _wrappedList.CopyTo((T[])array, index); 
    } 

    public int Count 
    { 
     get { return _wrappedList.Count; } 
    } 

    public bool IsSynchronized 
    { 
     get { return false; } 
    } 

    public object SyncRoot 
    { 
     get { return this; } 
    } 

    public IEnumerator GetEnumerator() 
    { 
     return _wrappedList.GetEnumerator(); 
    } 
} 

Usage:

public System.Collections.IList GetList() 
{ 
    return new NonGenericList<MyDataRow>(this._mydata); 
} 
Problemi correlati