1

我正在尝试使用访客模式,我有以下内容:

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

访客 :

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
}

我打电话给访客的地方:

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

那么..我在哪里失去了参考?在 newItem = foundTag 之后 - 我希望在访问者的 foreach 中我会有新的价值 - 显然这不会发生。

编辑我想我找到了答案 - 在 foreach 中,变量是只读的。

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

4

2 回答 2

1

为此,首先“newItem”必须是“ref”。其次,您需要在委托调用后对更新的值做一些事情(枚举器不提供任何更新内容的能力)。但是无论如何,对集合的大多数更新都会破坏枚举器!

否则,您的替换“newItem”将不会对客户可见。但是,标签的属性(假设它是一个引用类型并且是可变的)将会发生变化。

为此, itemsToActOn 必须是IList<T>- 然后你可以使用:

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

或者如果你可以使用T Visit(T)

for(int i = 0 ; i < itemsToActOn.Count ; i++)
{
    itemsToActOn[i] = visitor.Visit(itemsToActOn[i]);
}
于 2008-11-12T08:52:10.490 回答
0

是的,你是对的——但我在那个地方使用了一个 IEnumerable,所以不能真正为它做一个 for 。

但是我想返回一个新列表而不是影响当前列表更正确。所以我正在使用来自 Jean-Paul S. Boodhoo 的 ValueReturningVisitor - 启发(采取?:))。

于 2008-11-12T09:02:52.450 回答