2012-03-13 99 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()); 
}