7
votes

Reach and Linq Query - Besoin d'aide pour essayer de comprendre s'il vous plaît

J'ai une requête LINQ, les résultats dont je ithétiez dans une boucle de foresach.

La première est une requête qui attrape une collection de commandes à partir d'un panneau de mise en page de table, j'ai ensuite itérer sur la collection et retirez le Contrôles de TablealayOntPanel Ainsi: P>

        string[] strs = { "d", "c", "A", "b" };
        List<string> stringList = strs.ToList();

        var allitems = from letter in stringList
                       select letter;

        foreach (string let in allitems)
        {
            stringList.Remove(let);

        }


0 commentaires

3 Réponses :


10
votes

Pourquoi le premier exemple ne fait-il pas exploser aussi?

Le ienumerator Implémentation dans TableLayOntPanel1.Controls n'effectue pas les chèques appropriés pour voir si la collection a été modifiée. Cela ne signifie pas que c'est une opération sûre (car les résultats ne sont pas appropriés), mais plutôt que la classe n'était pas mise en œuvre de manière à soulager une exception (comme cela devrait probablement).

L'exception qui est soulevée lorsque vous énumérer via une liste et supprimer un élément est réellement soulevée par le Liste .Nenumerator Type et n'est pas une fonctionnalité de langue" d'usage général ".

Notez que ceci est un Nice Feature de la liste .enumerator Type, comme le ienumerator documentation indique explicitement:

Un énumérateur reste valable tant que la collection reste inchangée. Si des modifications sont apportées à la collection, telles que l'ajout, la modification ou la suppression des éléments, l'énumérateur est irrecoupé et son comportement n'est pas défini.

Bien qu'il n'y ait aucun contrat nécessitant une exception à lancer, il est bénéfique pour les implémentations de le faire lorsque vous entrez dans le domaine du «comportement indéfini».

Dans ce cas, le TableLayoutControlCollection La mise en œuvre de l'énumérateur de classe n'est pas Effectuer les chèques supplémentaires, vous voyez donc ce qui se passe lorsque vous utilisez une fonctionnalité où le «comportement est indéfini». (Dans ce cas, il élimine tout autre contrôle.)


5 commentaires

La raison de cette question n'est-elle pas liée au fait que énumérable.oftype est mis en œuvre à l'aide d'une exécution différée, d'où la séquence change toujours sur chaque énumération?


@Timschmelter Eh bien, detype consiste simplement à énumérer directement l'utilisation de l'énumérateur source directement - tandis que cela ne se produise pas, la même chose se produirait si vous énumérez les objets et mettez le chèque à l'intérieur de la boucle. L'énumérateur sous-jacent n'effectue pas de vérifier si la collection de contrôle est modifiée.


@ Timschmelter: Je soupçonne que toutes les opérations LINQ pourraient être supprimées du code postal d'origine et cela se comporterait exactement de la même manière. Comme le dit Reed, cela résulte de la mise en œuvre de l'énumérateur. Detype n'a rien à voir avec ça.


C'est génial mec, merci. Donc, dans mon 1ère cas, l'expression LINQ étant-elle réévaluée sur chaque itération de la boucle de Foreach? Ou est-ce que LINQ obtient l'ienumerator de la collection TableLayOntPanel.Controls?


@John il n'est pas réévalué. detype obtient le ienumerator à partir de TableLayOntPanel.Controls et l'enveloppe dans son propre énumérateur, qui est ensuite énuméré une fois une fois < / I> pendant votre foreach boucle.



2
votes

Donc, dans mon 1ère cas, l'expression LINQ étant réévaluée sur chaque itération de la boucle de forach? ou est linq obtenir l'ienumerator de la collection TableLayOnyOntPanel.Controls? P>

Pensez-y comme s'il se passait comme ceci, ce qui est ce qui se passe dans vos deux cas: p> xxx pré>

Le pseudo code ci-dessus illustre que comme vous essayez de supprimer un Article Vous êtes essentiellement au milieu d'une énumération de la collection code> StringList code>. Ce que Reed dit est que dans le second cas, l'énumérateur du StringList code> s'assure que personne ne se gâte avec elle pendant qu'il est au milieu de l'énumération. P>

Il dit que dans le CAS AVEC VOS CONTULLES, l'énumérateur des commandes s'allonge heureusement et ne vérifie pas pour voir si quelqu'un est monkeying avec ses données. P>

Pour complétude, comparez ces deux exemples: P>

Cette requête Pour lettres code> sera revaluée chaque fois que les lettres code> sont touchées, ce qui inclut l'heure à laquelle nous sommes dans la boucle de Foreach: P>

    List<string> letters = (from letter in stringList select letter).ToList()

    // because we ran ToList(), we will no longer enumerate stringList
    foreach (string l in letters) 
    { 
        stringList.Remove(l); 
    } 


1 commentaires

Merci Brad. Je l'ai maintenant. @Touteux qui a répondu: merci, cela a vraiment effacé cette question dans mon esprit. Vous êtes top les gars!



0
votes

Essayez ceci:

var AllItems = (from Item in this.tableLayoutPanel1.Controls.OfType<ItemControl>() 
                select Item);  


  int totalCount = AllItems .Count;
   for (int i = 0; i < totalCount; i++)
       {
           AllItems .RemoveAt(0);
        }


0 commentaires