2008-11-12 9 views
1

Je suis en train d'utiliser le modèle des visiteurs et je comme suit:Où est-ce que je perds la référence?

public class EnumerableActions<T> : IEnumerableActions<T> 
{ 
private IEnumerable<T> itemsToActOn; 


public EnumerableActions (IEnumerable<T> itemsToActOn) 
{ 
    this.itemsToActOn = itemsToActOn; 
} 

public void VisitAllItemsUsing (IVisitor<T> visitor) 
{ 
    foreach (T t in itemsToActOn) 
    { 
    visitor.Visit (t);// after this, the item is unaffected. 
    } 
} 

Le visiteur:

internal class TagMatchVisitor : IVisitor<Tag> 
{ 
private readonly IList<Tag> _existingTags; 

public TagMatchVisitor (IList<Tag> existingTags) 
{ 
    _existingTags = existingTags; 
} 

#region Implementation of IVisitor<Tag> 

public void Visit (Tag newItem) 
{ 
    Tag foundTag = _existingTags.FirstOrDefault(tg => tg.TagName.Equals(newItem.TagName, StringComparison.OrdinalIgnoreCase)); 

    if (foundTag != null) 
    newItem = foundTag; // replace the existing item with this one. 
} 

#endregion 
} 

Et où j'appelle le visiteur:

IList<Tag> tags = ..get the list; 
tags.VisitAllItemsUsing(new TagMatchVisitor(existingTags)); 

Alors ... où est-ce que je perds la référence? après newItem = foundTag - Je m'attends à ce que dans le foreach du visiteur j'aurais la nouvelle valeur - évidemment, cela ne se produit pas.

Édition Je pense avoir trouvé la réponse - dans une variable foron, readonly.

http://discuss.joelonsoftware.com/default.asp?dotnet.12.521767.19

Répondre

1

Pour que cela fonctionne, d'une part "newItem" devrait être "ref". Deuxièmement, vous devez faire quelque chose avec la valeur mise à jour après l'appel du délégué (un énumérateur n'offre aucune possibilité de mettre à jour le contenu). Mais la plupart des mises à jour des collections vont briser les enquêteurs de toute façon!

Le remplacement de "newItem" ne sera pas visible par le client. Cependant, les modifications apportées aux propriétés du tag (en supposant qu'il s'agit d'un type de référence et mutable) le seront.

Pour que cela fonctionne, itemsToActOn faudrait IList<T> - vous pouvez alors utiliser:

for(int i = 0 ; i < itemsToActOn.Count ; i++) 
{ 
    T value = itemsToActOn[i]; 
    visitor.Visit(ref t) 
    itemsToActOn[i] = value; 
} 

Ou si vous pouvez utiliser T Visit(T)

for(int i = 0 ; i < itemsToActOn.Count ; i++) 
{ 
    itemsToActOn[i] = visitor.Visit(itemsToActOn[i]); 
} 
0

Oui, vous avez raison - mais je J'utilise un IEnumerable à cet endroit, donc je ne peux pas vraiment le faire.

Cependant je suppose qu'il est plus correct de retourner une nouvelle liste au lieu d'affecter la liste actuelle. Donc j'utilise un ValueReturningVisitor - inspiré (pris? :)) de Jean-Paul S. Boodhoo.

+0

Dans ce cas, considérez la méthode LINQ Enumerable.Select (pour IEnumerable ) ou la liste .ConvertAll - les deux effectuent ce type de projection. –