2012-03-13 146 views
0

我希望以线程安全的方式迭代集合。我觉得这是convieniant有一个方法叫一个更好的方式使用函数委托通过行动委托

/// <summary> 
/// This visits all items and performs an action on them in a thread manner 
/// </summary> 
/// <param name="visitAction">The action to perform on the item</param> 
public void VisitAllItems(Action<Item> visitAction) { 
    lock (listLock) { 
     foreach (Item item in this.ItemList) { 
      visitAction.Invoke(item); 
     } 
    } 
} 

它的一个例子是使用可

/// <summary> 
/// Saves each item in the list to the database 
/// </summary> 
protected static void SaveListToDatabase() { 
    this.VisitAllItems(item => { 
     bool itemSavedSuccessfully = item.SaveToDB(); 
     if(!itemSavedSuccessfully) { 
      //log error message 
     } 
    }); 
} 

它的另一个例子我们使用将

/// <summary> 
/// Get the number of special items in the list. 
/// </summary> 
protected int GetNumberOfUnsynchronisedItems() { 
    int numberOfSpecialItems = 0; 
    this.VisitAllItems((item) => { 
     numberOfSpecialItems += item.IsItemSpecial() ? 1 : 0; 
    }); 
    return numberOfSpecialItems; 
} 

但我敢肯定有是编写VisitAllItems方法以使用Func<>而不是Action<>委托来返回此值的更好方法。我已经尝试了几件事情,但最终出现编译错误。

任何人都可以看到一个整洁的方式来实现这种方法?

感谢, 麦金太尔

回答

2

这一切都取决于使用情况,所以很难说究竟是什么会对你有用。但有一种方法是为集合中的每个项目返回一个结果,然后使用LINQ来合并结果。

public IEnumerable<TResult> VisitAllItems<TResult>(
    Func<Item, Result> visitfunction) 
{ 
    var result = new List<TResult>(); 
    lock (listLock) 
    { 
     foreach (Item item in ItemList) 
      result.Add(visitfunction(item)); 
    } 
    return result; 
} 

通常情况下,我会用yield return代替手动创建List<T>的,但我认为这是更好的这种方式在这里,因为lock的。

的用法是这样的:

protected int GetNumberOfUnsynchronisedItems() 
{ 
    return VisitAllItems(item => item.IsItemSpecial()) 
        .Count(isSpecial => isSpecial); 
} 
+0

由于双方svick和@jonskeet。根据我的情况,我理解你的两个解释,并且两者似乎都是合适的。除非我能说服别人,否则我已经给了你点,没有比有人需要挑战jon更好的理由。欢呼声 – ajmccall 2012-03-14 00:23:39

+0

你不应该根据声誉得分来决定,而只能根据答案本身来决定。此外,你可以(也应该)通过提升他们来“给予多于一个答案的积分”。你应该提出所有你认为好或有用的答案。 – svick 2012-03-14 00:27:20

+0

公平点(http://blog.stackoverflow.com/2010/01/stack-overflow-where-we-hate-fun/)。但我接受的答案仍然存在。 +1以及@JonSkeet。 – ajmccall 2012-03-14 06:12:10

2

你可以遵循Aggregate模型,但它不会是非常愉快的使用:

public TAccumulate VisitAllItems<TAccumulate>(TAccumulate seed, 
    Func<Item, TAccumulate, TAccumulate> visitor) { 
    TAccumulate current = seed; 
    lock (listLock) { 
     foreach (Item item in this.ItemList) { 
      current = visitor(current, item); 
     } 
    } 
    return current; 
} 

... 

protected int GetNumberOfUnsynchronisedItems() { 
    return VisitAllItems(0, 
     (count, item) => count + item.IsItemSpecial() ? 1 : 0); 
} 

多少不同的聚合功能,你真的需要?例如,如果的你只是在数着时间,你可能想:

public void VisitAndCount<TAccumulate>(Func<Item, bool> visitor) { 
    int count = 0; 
    lock (listLock) { 
     foreach (Item item in this.ItemList) { 
      if (visitor(item)) { 
       count++; 
      } 
     } 
    } 
    return count; 
} 

则:

protected int GetNumberOfUnsynchronisedItems() { 
    return VisitAndCount(item => item.IsItemSpecial()); 
}