Where am I losing my link?

I am trying to use the visitor template and I have the following:

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.
  }
}

      

Visitor:

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
}

      

And where do I call the visitor:

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

      

So where am I losing my link? after newItem = foundTag - I expect the visitor to have a new value in the foreach - obviously this is not happening.

Edit I think I found the answer - in foreach, the variable is only readable.

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

+1


source to share


2 answers


For this to work, first, "newItem" must be "ref". Second, you will need to do something with the updated value after the delegate has been called (the enumerator does not offer the ability to update the content). But most updates to collections will crash the counters anyway!

Otherwise, your replacement "newItem" will not be visible to the client. However, changes to the properties of the tag (assuming it is a reference type and mutable) will.

For this, itemsToActOn must be IList<T>

- then you can use:



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

      

Or if you can use T Visit(T)

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

      

+1


source


Yes, you are correct, but I am using IEnumerable at this point, so it actually isn't.



However, I think it is more correct to return a new list rather than influence the current one. So I am using ValueReturningVisitor - inspired (taken? :)) from Jean-Paul S. Boodhoo.

0


source







All Articles