2009-09-10 25 views
3

我有一個用例,我必須退訂一個事件。但在取消訂閱之前,我想確定這個人是否已經被動手吸引到這個事件上。如何找出是否有人訂閱了一個活動?

請讓我知道我可以做到這一點?

+6

它是一個非常環境的具體問題 - 所以你應該提供一些關於語言/框架/平臺的信息 – 2009-09-10 03:54:06

+2

什麼語言? – 2009-09-10 03:55:25

+0

艾米特,你需要編輯你的問題,提供更多關於你的問題的信息。 – 2009-09-10 04:24:12

回答

1

示例類Publisher提供了一個事件發佈。 IsRegistered方法查詢給定類實例的事件附加事件處理程序,如果此類實例至少有一個註冊/附加事件處理程序,則返回true。 重寫IsRegistered方法的作用與靜態類型相同。

把這段代碼放到一個控制檯應用程序項目中,然後按F5進行調試,試試看。

internal class Publisher 
{ 
    internal event EventHandler<EventArgs> Publish; 

    internal bool IsRegistered(Type type) 
    { 
     if (Publish == null) return false; 
     // 
     return (from item in Publish.GetInvocationList() where item.Target == null & item.Method.DeclaringType == type select item).Count() > 0; 

    } 
    internal bool IsRegistered(object instance) 
    { 
     if (Publish == null) return false; 
     // 
     return (from item in Publish.GetInvocationList() where item.Target == instance select item).Count() > 0; 
    } 

    static int Main(string[] args) 
    { 
     Publisher p = new Publisher(); 
     // 
     p.Publish += new EventHandler<EventArgs>(static_Publish); 
     p.Publish += new EventHandler<EventArgs>(p.instance_Publish);    
     // 
     Console.WriteLine("eventhandler static_Publish attach: {0}", p.IsRegistered(typeof(Program))); 
     Console.WriteLine("eventhandler instance_Publish attach: {0}", p.IsRegistered(program)); 
     // 
     return 0; 
    } 

    void instance_Publish(object sender, EventArgs e) 
    { 

    } 
    static void static_Publish(object sender, EventArgs e) 
    { 

    } 
}` 
+0

當我們註冊一個事件時,每次我們安裝一個新的Delegate實例,所以我不會讓委託獲取調用列表。 不是嗎? – Amit 2009-09-10 08:51:30

+0

我們不查詢委託實例本身,但它的目標屬性。 我們想知道A類是否向我們的事件(多播委託)註冊了一個事件處理程序,因此我們查詢了我們事件中的所有已註冊的代表以查找在Target屬性中具有我們的A類實例的代理,希望這有助於 – 2009-09-10 09:53:45

+0

是的,多數民衆贊成在需要:) 但我們又能如何實現這一目標? – Amit 2009-09-10 09:59:12

0

假設的pub/sub環境,只需撥打provider.Unsubscribe(事件類型,用戶),並讓供應商確定該用戶是否簽約與否

3

Microsoft

 // Wrap event invocations inside a protected virtual method 
     // to allow derived classes to override the event invocation behavior 
     protected virtual void OnRaiseCustomEvent(CustomEventArgs e) 
     { 
      // Make a temporary copy of the event to avoid possibility of 
      // a race condition if the last subscriber unsubscribes 
      // immediately after the null check and before the event is raised. 
      EventHandler<CustomEventArgs> handler = RaiseCustomEvent; 

      // Event will be null if there are no subscribers 
      if (handler != null) 
      { 
       // Format the string to send inside the CustomEventArgs parameter 
       e.Message += String.Format(" at {0}", DateTime.Now.ToString()); 

       // Use the() operator to raise the event. 
       handler(this, e); 
      } 
     } 

你尋找if(handler!= null)部分。它是null如果沒有任何用戶,非空如果有用戶。

+0

雖然您的文章是準確的,但他想檢查他是否已經爲該事件分配了*特定的*處理程序,而不是如果分配了任何處理程序(即它不爲空)。 – 2009-09-10 07:53:36

+0

是的,絲柔是對的。我想知道處理程序是否已連接。 – Amit 2009-09-10 08:48:38

0

有兩種方法可以做到這一點:

  1. 您可以創建一個新的委託鏈,與要取消訂閱,除去委託,並比較你保存它之前,你得到了一個。在您取消訂閱已訂閱的代理的情況下,您將返回一個新的代理鏈,但沒有該代理。如果您試圖取消訂閱尚未訂購的的代理商,則將返回與您所購買的相同的代理商。
  2. 您可以手動移動委託鏈來查看是否存在您想取消訂閱的委託。爲了簡單起見,這可以使用普通的Linq方法完成,如.Contains

第一種情況可能看起來像下面的代碼。這將在一個臨時變量中創建一個新的委託鏈,並且要刪除,刪除該委託,然後將該臨時鏈與現有鏈進行比較。如果他們一樣,代表不在場。

private EventHandler _Changed; 
public event EventHandler Changed 
{ 
    add 
    { 
     _Changed += value; 
    } 
    remove 
    { 
     EventHandler temp = _Changed - value; 
     if (_Changed == null || temp == _Changed) 
      throw new InvalidOperationException(
       "Delegate is not subscribed, cannot unsubscribe"); 
     _Changed = temp; 
    } 
} 

第二個像下面的代碼,這將只是看看你想取消訂閱的代表是否存在於代表鏈中。

private EventHandler _Changed; 
public event EventHandler Changed 
{ 
    add 
    { 
     _Changed += value; 
    } 

    remove 
    { 
     if (_Changed == null || !_Changed.GetInvocationList().Contains(value)) 
      throw new InvalidOperationException(
       "Delegate is not subscribed, cannot unsubscribe"); 
     _Changed -= value; 
    } 
} 

請注意,如果您願意,可以使用類似的代碼來處理代理被添加兩次的情況。