2012-09-19 28 views
1

目前,我用下面的代碼來實現的事件,在一類,即最多可有註冊它一個事件處理程序:單用戶事件

private event EventHandler<EventArgs> e_Foo; 

public event EventHandler<EventArgs> Foo { 
    add { 
     if (e_Foo != null && e_Foo.GetInvocationList().Any()) 
      throw new InvalidOperationException("Only one event handler may be registered at a time."); 
     e_Foo += value; 
    } 
    remove { 
     e_Foo -= value; 
    } 
} 

private void OnFoo() { 
    if (e_Foo != null) 
     e_Foo(this, EventArgs.Empty); 
} 
  • 有沒有更好的辦法?
  • 有沒有什麼辦法可以把它包裝在一個類中,所以我不需要複製和粘貼這麼多的代碼?
+1

訂閱多個事件處理程序有什麼問題? – dtb

+0

@dtb,這裏只有一個用戶是有道理的。忘記取消會導致衝突,所以我想強制執行此操作。 –

+0

我認爲你應該以某種方式解決這個問題,而不是通過改變事件的常規方式。順便說一句,你的代碼不能滿足你的要求,因爲委託實例可以有多個調用目標。 – dtb

回答

1

事件只是用特殊語義公開委託屬性的一種特殊方式:不是設置值,而是添加和刪除處理程序。如果這種行爲不適合你,那麼試圖從事件中刪除它只是造成不必要的複雜性。相反,爲什麼不直接將回調作爲委託屬性公開,避免首先添加不想要的行爲?

public Action<T1, T2> Foo {get; set;} 

private void OnFoo(T1, T2) 
{ 
    var handler = Foo; 
    if(handler != null) handler(T1, T2); 
} 

這樣,當有人將OnFoo它將使用正常的產權語​​義和更換委託實例,而不是把它扔在一堆。它沒有擺脫多播,但它聽起來不像我這樣,這真的是你的問題。

+0

事件看起來像處理回調的正常方法,所以我從來沒有想到這一點。這是我現在使用的,它絕對簡化了事情。我仍然與他們有一個非多播委託類型,但。 –

+0

@JonathonReinhart我也曾擔心過這個問題,但我已經用它做了我的安寧,並且認爲關心它是一種代碼味道。理想情況下,如果您的對象被正確封裝,那麼您不應該有任何理由關心其用戶是否正在編寫代表。無論如何,這只是一些無法預防的東西。考慮'myObject.Callback =()=> {x.Foo(); y.Bar(); }' –

1

這確實應該評論,但我需要編寫代碼:

private void OnFoo() { 
    if (e_Foo != null) 
     e_Foo(this, EventArgs.Empty); 
} 

引入了一個潛在的競爭條件,因爲調用列表可以檢查與實際調用之間改變。你可能最終調用null。它應該是:

private void OnFoo() { 
    var fuFoo = e_Foo; 
    if (fuFoo != null) 
     fuFoo(this, EventArgs.Empty); 
} 

我想一個不太容易出錯的方法是更好的方法。我贏了!

+0

謝謝。我在調用之前看過局部變量副本,但忘記在這裏實現。當然,整個單用戶問題依然存在。 –

0

我不認爲這是可能的減少代碼很多,但是你可以把檢查該做的工作適合你,或返回處理,像這樣的方法:

public EventHandler<T> HookUp<T>(EventHandler<T> myEvent, EventHandler<T> myMethod) 
    where T : EventArgs 
{ 
    if (myEvent != null && myEvent.GetInvocationList().Any()) 
     throw new InvalidOperationException("Only one event handler may be registered at a time."); 
    return myMethod; 
} 

private event EventHandler<EventArgs> e_Foo; 

public event EventHandler<EventArgs> Foo 
{ 
    add { e_Foo += HookUp(e_Foo, value); } 
    remove { e_Foo -= value; } 
} 

你可以實現一個在某些擴展方法中具有所有邏輯的接口,或者繼承一個抽象類。但是,那麼您必須爲每個想要的事件數量提供多個接口(ISingleSubscriberOneISingleSubscriberTwoISingleSubscriberThree等等)。

0

我不確定在您的情況下是否可行,但我會將事件代碼合理地分配給一個Action變量並將該事件鏈接到該Action。然後,用戶將只能夠更改該操作,並且不會真正更改我的事件中註冊的事件。該事件只會鏈接到該操作,以便您可以更改該操作,但是您不能同時擁有2個操作。

只是一個想法。還沒有喝咖啡,所以這可能根本不合適......