2010-09-23 18 views
4

我有下面的代碼: -有了這個.NET事件,可以通過這個IList實例嗎?

while (....) 
{ 
    var foo = DoTheFooShakeShakeShake(..); 
    foos.Add(foo); // foos is an IList<Foo>, btw and is new'd, above. 

    if (foos.Count % 100 == 0) 
    { 
     var e = new CustomFooEventArgs { UserId = whatever, Foos = foos }; 
     OnFooPewPew(this, e); 
     foos.Clear(); 
    } 
} 

// We still might have some foo's left over.. so send em off also. 
// Excuse the woeful var names, below. 
var e2 = new CustomFooEventArgs { UserId = whatever, Foos = foos }; 
OnFooPewPew(this, e2); 

所以,我抓住所有的foo替換了一會兒/循環狀態。然後,每一百美元我都會發起一個事件,它將foo的列表傳遞給訂閱者。然後我清除這個foos列表。一旦循環完成,我然後將任何剩餘的foo發送給訂閱者。

所以 - 如果我點燃一個事件,其中包含foo的列表...然後我清除該列表..這是否意味着訂戶可能獲得該列表,現在是空的?我是否應該通過列表的COPY ...然後清除原始列表?

回答

5

忘記清理,事實上你根本不會改變清單,這會對預訂事件的對象造成嚴重破壞。 如果他們堅持返回列表,您將隨時更改數據,只要您將其添加到列表就可以清除它。

你不僅可以把用戶弄亂了,他們可以用,因爲他們可以改變列表並影響你自己的過程。

如果這不是我們想要的行爲(而且我不認爲它是這樣),那麼您將不想發送一份副本,而是發送一個IEnumerable<Foo>或。因爲即使你發送了一份副本,如果你有多個訂閱者,他們也會收到相同的副本,所以他們的突變仍然會給彼此造成巨大的破壞。

+0

可變的收藏...肆虐...這是真的... – sloth 2010-09-23 08:08:34

2

當你清除列表時,事件處理程序已經被執行(它們被同步調用),所以這不是問題。

但是,您應該避免傳遞列表本身,您應該傳遞一份副本。否則事件用戶可以保持對列表的引用,並以不可預知的方式混淆它...

+0

你可以讓異步事件被觸發/處理嗎? – 2010-09-23 00:21:24

+0

是的,如果你用BeginInvoke調用處理程序。但那是你*控制的東西,而不是訂戶 – 2010-09-23 00:24:55

2

假設你可以控制所有訂閱者,並且只在一個線程上工作,那麼很好。否則,如果您無法控制訂閱者(誰知道他們會做什麼?),或者您正在使用多線程處理髮送的集合,則應考慮發送該集合的副本。

1

我寧願有意見要做到這一點,但沒有:-)

Anthony's answer,在這裏你沒有接收器的控制偏執擴展的聲譽,是保證列表複製你傳遞的是一個ReadOnlyCollection<Foo>(*)。如果您僅僅將您的列表複製爲另一個List<Foo>或其他可變集合,即使CustomFooEventArgsFoos定義爲非易變接口(例如IEnumerable<Foo>),特別卑鄙的接收方也可以將Foos作爲List<Foo>投射並對其進行變異。

至於Thomas' answer,使用BeginInvoke停止事件接收器產生一個異步任務,除非我遺漏了一些東西,沒有什麼能夠停止。 (*)我可能會將它定義爲CustomFooEventArgs中的IEnumerable<Foo>,但使用的事實是ReadOnlyCollection<Foo>是一個實現細節恕我直言。

相關問題