2011-09-12 7 views
3

J'ai la fonction récursive suivante qui est utilisée pour rechercher un arbre hiérarchique et supprimer des objets trouvés dans une liste:Retrait de la liste récursive en C#

private List<Tag> RemoveInvalidTags(Device device, List<Tag> tags) 
{ 
    var childDevices = device.ChildDevices.Select(c => c.ChildDevice); 

    foreach (var child in childDevices) 
    { 
     tags.Remove(child.Tag); 
     RemoveInvalidTags(child, tags); 
    } 

    return tags; 
} 

Ce que je m'y attendais à faire est de retirer tous les enfants à ce niveau dans la liste des balises, appelez la fonction récursivement pour vos enfants, puis retournez cette liste au niveau précédent.

Est-ce que cela va passer la liste de balises par référence et modifier la liste originale passée? Ou devrais-je faire quelque chose le long des lignes de

validTags = CollectValidTags(child, tags); 

et en additionnant toutes les listes retournées?

Répondre

3

Est-ce que ce passe la liste des balises par référence

No. Objet de la liste est passée "en valeur" (mais voir plus loin). (ref ou out est nécessaire pour "pass by reference" en C#, mais cela ne se fait ici, ni besoin d'être.)

et modifier la liste passée original?

Oui. En effet, l'objet de liste est transmis. Et cet objet de liste est muté. Passer un type de référence (tout ce qui est défini avec class) jamais effectue implicitement une copie/un clone/un doublon. Un objet est ce qu'il est.

Maintenant, retour à "pass by value": la "valeur passée" est la valeur de la "référence" (interne, pas besoin de s'en préoccuper): cette stratégie d'appel est mieux connue sous le nom Call/Pass By Object Sharing dans une langue comme C#. Le même objet est partagé (comme s'il était affecté à deux variables différentes). (Types de valeur - un struct - sont différents en ce sens qu'ils (souvent) sont copiés/dupliqués sur la pile, mais un List<T> est un class.)

Ou devrais-je faire quelque chose le long les lignes de

elle dépend de la sémantique souhaitées. Est-ce que l'appelant s'attendre à les effets secondaires directement ou indirectement? L'effet secondaire de la mutation peut-il entraîner des scénarios inattendus? Assurez-vous de le documenter de toute façon. (Je préfère la manière qui garantit que l'objet initial n'est pas muté.)

Espérons que cela efface certaines choses.

Bonne codification.

+0

Veuillez expliquer -1. Cela ne me dérange pas, mais sans explication, cela ne sert à rien. –

+2

Mon seul pointeur ici est de savoir comment vous vous référez à l'objet "liste" qui est passé par valeur. C'est trompeur au mieux. L'objet est ce qui est assis sur le tas. La référence est passée en valeur, oui, mais continuer à dire * list object * me semble étrange. BTW, j'ai enlevé le -1 après l'avoir relu. Je vous ai mal compris un peu en raison de la question que je mentionne ci-dessus la première fois. –

+0

@ Ed S. J'espère que les modifications ont nettoyé cela. J'essayais de me concentrer sur le fait qu'un objet est ... lui-même, peu importe le nom (variable) qu'il passe. Cela commence quand même un peu fort. –

0

Réponse courte - votre code fera ce que vous voulez.Longue réponse - vous devriez lire les descriptions de ce que fait le mot-clé ref. Je vous suggère de lire autant de descriptions que possible; il y a beaucoup de manières différentes de l'articuler ("j'aime penser à lui comme ...") et certains travailleront pour vous pendant que d'autres ne le feront pas. Si vous lisez beaucoup de descriptions (de personnes qui le comprennent) alors une sorte de compréhension devrait geler pour vous.

Voici une liste pour vous aider à démarrer:

2

Dans votre code, vous modifiez les éléments votre paramètre tags et en repassant la liste modifiée comme yo résultat. Vous voulez éviter de modifier les listes de cette manière - en particulier dans les boucles où cela peut vous causer du chagrin dans de nombreuses situations.

J'ai une alternative basée sur LINQ pour vous.

Si je comprends l'intention de votre code que vous voulez faire quelque chose comme ceci:

Func<Device, IEnumerable<Device>> flatten = null; 
flatten = d => 
{ 
    return (new [] { d }).Concat(
     from c in d.ChildDevices 
     from f in flatten(c) 
     select f); 
}; 

var collectedValidTags = flatten(device).Select(d => d.Tag); 

var result = tags.Except(collectedValidTags).ToList(); 

Cette approche ne passe pas votre liste de balises autour donc il n'y a aucune chance de modifier votre liste initiale.

Est-ce que cela aide?

+0

Je ne peux pas choisir votre réponse comme réponse correcte car elle ne répond pas réellement à ma question initiale, cependant je vous ai donné un upvote parce que le vôtre est une meilleure solution. À votre santé. – link664

+0

@ link664 - Tout à fait compris. Je ne m'attendais pas à répondre directement à votre question, mais plutôt à vous donner une manière propre et fonctionnelle de faire ce que vous vouliez sans avoir à manipuler des collections mutables. – Enigmativity