19 votes

Conversion de IList<T> en IList non générique

Je mets en œuvre IListSource qui nécessite une méthode GetList() avec la signature suivante :

IList GetList()

J'utilise .NET framework 2 et je veux retourner un objet qui implémente IList comme suit :

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

Mais je reçois une erreur de compilation disant : Cannot implicitly convert type MyData to System.Collections.IList .

Si je crée un nouveau liste de type List<MyDataRow> le remplit et renvoie cet objet liste, et cela fonctionne. En d'autres termes, cela fonctionne :

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

Mais il semble très inefficace de devoir recréer la liste juste pour l'obtenir à partir du type IList<T> a IList . Comment se fait-il que je puisse renvoyer un List<MyDataRow>' from 'GetList() mais pas un IList<MyDataRow> ? Quelqu'un connaît-il un moyen pour moi de renvoyer la IList<MyDataRow> sans recréer une nouvelle liste ?

UPDATE :

En _mydata est déclarée :

private MyData _mydata;

Et MyData est déclarée :

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

15voto

James Points 40024

Comment se fait-il que je puisse renvoyer un List<MyDataRow> de GetList() mais pas un IList<MyDataRow>

Cela s'explique par le fait que List<T> met en œuvre IList , IList<T> ne peut pas être lancé vers IList il s'agit de deux interfaces distinctes. Pour répondre à votre question :

Quelqu'un connaît-il un moyen pour moi de renvoyer la IList<MyDataRow> sans recréer une nouvelle liste ?

Si le type concret implémente IList (qui List<T> ), vous pouvez alors le lancer explicitement, par exemple.

return (IList)this.mydata;

Mise à jour

Sur la base de votre mise à jour, vous devrez mettre à jour MyData pour mettre en œuvre IList sinon vous n'avez pas d'autre choix que de renvoyer une nouvelle collection qui fait le mettre en œuvre.

Par ailleurs, si MyData est en effet une liste générique, alors je suggérerais de la faire hériter de List<T> De cette manière, vous bénéficiez d'une plus grande flexibilité et d'une meilleure compatibilité dès le départ.

class MyData : List<MyDataRow>
{
}

4voto

Xharze Points 2654

En MyData doit implémenter la classe IList ainsi que la version générique IList<T> .

class MyData : IList<MyDataRow>, IList
{
}

4voto

shambulator Points 3765

IList<T> ne s'étend pas IList Il n'est pas raisonnable de s'attendre à ce que chaque implémentation de la version générique offre le même contrat que la version non générique. S'il étendait IList quelqu'un pourrait prendre la valeur renvoyée par GetList et s'attendre raisonnablement à appeler, par exemple Add(DateTime.Now) ou Add(Thread.CurrentThread) . C'est ce que IList promet.

C'est la raison pour laquelle la copie de votre liste dans un List<T> œuvre - List<T> met en œuvre à la fois et lance lorsque son interface (explicitement implémentée) IList sont appelées avec des types de paramètres inappropriés.

Si vous pouvez vous permettre de renvoyer IEnumerable Faites-le à la place. Si vous pouvez renvoyer IList<MyDataRow> au lieu de cela, alors faites-le. Si vous avez vraiment besoin d'un IList retournera, puis mettre en œuvre l'interface et gérer les cas de non-recours. MyDataRow de manière appropriée.

4voto

max Points 16106

Soit mettre en œuvre IList sur votre classe de collecte de données ou créez un adaptateur, qui englobe la fonction IList<T> et met en œuvre 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();
    }
}

Utilisation :

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

2voto

David W Points 5303

S'il était possible de convertir un IList<T> en un IList directement, vous pourriez renvoyer une liste qui pourrait (par exemple) être "contaminée" par des éléments non T par l'intermédiaire de son Add(object) méthode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X