2
votes

IList > n'accepte pas List >?

List implémente IList donc j'espère que IList acceptera un objet List mais pourquoi IList> n'accepte pas List>?

static IList<int> List_1()
    {
        List<int> list = new List<int> { 1,2,3,3,4,5};

        return list;
    }

    static IList<IList<int>> List_2()
    {
        List<List<int>> parent = new List<List<int>>();
        List<int> list = new List<int> { 1, 2, 3, 3, 4, 5 };
        parent.Add(list);

        return parent; //compiler error CS0266
    }


9 commentaires

Comprenez-vous pourquoi List n'accepte pas List ?


return (IList >) parent;


@jdweng: Cela ne fonctionnera pas, vous obtiendrez une exception d'exécution.


Copie possible de Pourquoi ne puis-je pas diffuser depuis une liste pour lister ?


@ SᴇM Il ne s'agit pas de convertir un type en un type d'objet, mais IList et List.


Le double possible de stackoverflow.com/questions/26501312/...


@vsarunov Vous savez bien, ce compilateur donne une erreur, car il ne peut pas convertir de List> en IList> ?


@ SᴇM Cela a-t-il à voir avec la conversion de List en List ? Si j'avais ce problème, ce serait une simple instruction linq ou utiliser simplement "as" ou "is" et vérifier si vous pouvez le lancer. C'est spécifiquement IList et List.


@vsarunov Oui, car MyClass dérivé de object , comme List dérivé de IList . Donc si vous avez par exemple une méthode qui retourne List , vous ne pouvez pas retourner List sans cast.


5 Réponses :


0
votes

Pourquoi alors List implémente IList?

C'est un peu étrange, car List pour tout type autre que object ne remplir l'intégralité du contrat d'IList. C'est probablement pour faciliter les choses les personnes qui mettent à jour l'ancien code C # 1.0 pour utiliser des génériques; ces gens assuraient probablement déjà que seuls les bons types entraient leurs listes. Et la plupart du temps, lorsque vous passez un IList, c'est pour que l'appelé puisse accéder par index à la liste, pas pour que il peut ajouter de nouveaux éléments de type arbitraire.


0 commentaires

1
votes

Supposons que cela fonctionne. Votre code client est:

static IEnumerable<IEnumerable<int>> List_2()
{
    List<List<int>> parent = new List<List<int>>();
    List<int> list = new List<int> { 1, 2, 3, 3, 4, 5 };
    parent.Add(list);

    return parent; // no error, this works
}

Puisque le contrat permet d'ajouter au résultat tout ce qui est IList , vous pourriez éventuellement avoir

var result = List_2();
result.Add( new MyCustomIList() );

puis

public class MyCustomIList : IList<int>
{
    ...
}

Mais c'est faux!

Votre résultat est une liste de List , vous ne devriez pas être autorisé à ajouter autre chose que List ou ses dérivés là-bas. Cependant, vous avez pu ajouter MyCustomIList qui n'est pas lié à la List .

Si vous avez besoin une vue d'ensemble du problème, en savoir plus sur covariance et contravariance .

Le problème fondamental dans cet exemple particulier vient de l'opération Add . Si vous n'en avez pas besoin, IEnumerable fera l'affaire

var result = List_2();

Cela a été déjà couvert .


0 commentaires

0
votes

Je ne sais pas pourquoi vous voulez renvoyer exactement IList> , mais une façon de le faire est d'utiliser Méthode Cast () :

return parent.ConvertAll(x => (IList<int>)x);

Ou ConvertAll () method :

static IList<IList<int>> List_2()
{
    List<List<int>> parent = new List<List<int>>();
    List<int> list = new List<int> { 1, 2, 3, 3, 4, 5 };
    parent.Add(list);

    return parent.Cast<IList<int>>().ToList();
}

Les deux méthodes seront exécutées tous les éléments, et les cast / convertir dans un type donné, donc je pense qu'il serait préférable de retourner IList> à la place (si c'est possible).

p >


0 commentaires

0
votes

Le problème vient de votre méthode return type . Modifiez la signature de votre méthode pour revenir à IList> plutôt que de renvoyer IList>

static IList<List<int>> List_2()
    {
        List<List<int>> parent = new List<List<int>>();
        List<int> list = new List<int> { 1, 2, 3, 3, 4, 5 };
        parent.Add(list);

        return parent; //no compiler error
    }

Maintenant cela fonctionnera bien car votre méthode renvoie maintenant un IList de List


0 commentaires

2
votes

C'est parce que

List implémente IList mais

List > n'implémente pas IList>

C'est pourquoi votre première méthode fonctionne comme prévu et la seconde non.

Modifiez simplement votre déclaration de la liste dans la deuxième méthode à

List<IList<int>> parent = new List<IList<int>>();

Et c'est le cas de la covariance et de la contravariance.

Les paramètres de type générique supportent la covariance et contravariance mais vous devez définir de cette manière

Par docs.microsoft.com

La covariance et la contravariance sont des termes qui font référence à la capacité d'utiliser un type plus dérivé (plus spécifique) ou un type moins dérivé (moins spécifique) que celui spécifié à l'origine. Les paramètres de type générique prennent en charge la covariance et la contravariance pour offrir une plus grande flexibilité dans l'attribution et l'utilisation de types génériques


0 commentaires