执行Postsharp EventInterceptionAspect防止事件处理程序挂钩两次

问题描述:

如果您使用相同的订阅多次订阅.net事件,那么您的订阅方法将被调用与订阅相同的次数。如果你只退订一次,那么它只会减去一次。意思是你必须取消订阅订阅的次数,否则你会被告知。有时你不想这样做。执行Postsharp EventInterceptionAspect防止事件处理程序挂钩两次

为了防止事件处理程序被挂钩两次,我们可以实现以下事件。现在

private EventHandler foo; 
public event EventHandler Foo 
{ 
    add 
    { 
     if(foo == null || !foo.GetInvocationList().Contains(value)) 
     { 
      foo += value; 
     } 
    } 
    remove 
    { 
     foo -= value; 
    } 
} 

我想实现Postsharp EventInterceptionAspect使这种解决方案通用的,这样我就可以在每一个事件申请PreventEventHookedTwiceAttribute节省大量代码。但我无法弄清楚如何在添加中检查以下条件的第二部分。我的意思是foo.GetInvocationList()。包含(值)。我的PreventEventHookedTwiceAttribute如下所示。

[Serializable] 
public class PreventEventHookedTwiceAttribute: EventInterceptionAspect 
{ 
    public override void OnAddHandler(EventInterceptionArgs args) 
    { 
     if(args.Event == null || secondConditionRequired) // secondConditionRequired means it is required.    
     { 
      args.ProceedAddHandler(); 
     } 
    } 
} 

我不需要重写OnRemoveHandler,因为默认功能就够了。

+0

你不希望同一个订户两次订阅两次,或者你只想要一个订户周期? – 2012-04-17 15:17:21

+0

@DustinDavis:谢谢你的提问。我想阻止同一订阅者订阅两次。像这样: void EventHandler(){.....} Main() { \t someClass.SomeEvent + = EventHandler; \t someClass.SomeEvent + = EventHandler; } 如果我使用正常事件,那么EventHandler方法将被调用两次。但是如果我使用在Foo中实现的模式,那么它只会被调用一次。 – Saghar 2012-04-18 14:28:48

+0

@DustinDavis:我解决了这个问题。请看我的答案。 – Saghar 2012-04-20 16:19:13

这个班有诀窍。

[Serializable] 
public class PreventEventHookedTwiceAttribute: EventInterceptionAspect 
{ 
    private readonly object _lockObject = new object(); 
    readonly List<Delegate> _delegates = new List<Delegate>(); 

    public override void OnAddHandler(EventInterceptionArgs args) 
    { 
     lock(_lockObject) 
     { 
      if(!_delegates.Contains(args.Handler)) 
      { 
       _delegates.Add(args.Handler); 
       args.ProceedAddHandler(); 
      } 
     } 
    } 

    public override void OnRemoveHandler(EventInterceptionArgs args) 
    { 
     lock(_lockObject) 
     { 
      if(_delegates.Contains(args.Handler)) 
      { 
       _delegates.Remove(args.Handler); 
       args.ProceedRemoveHandler(); 
      } 
     } 
    } 
} 

示例显示差异的用法如下所示。

class Program 
    { 
     private static readonly object _lockObject = new object(); 
     private static int _counter = 1; 

     [PreventEventHookedTwice] 
     public static event Action<string> GoodEvent; 


     public static event Action<string> BadEvent; 

     public static void Handler (string message) 
     { 
      lock(_lockObject) 
      { 
       Console.WriteLine(_counter +": "+ message); 
       _counter++; 
      } 
     } 

     static void Main(string[] args) 
     { 
      GoodEvent += Handler; 
      GoodEvent += Handler; 
      GoodEvent += Handler; 
      GoodEvent += Handler; 
      GoodEvent += Handler; 
      Console.WriteLine("Firing Good Event. Good Event is subscribed 5 times from the same Handler."); 
      GoodEvent("Good Event is Invoked."); 

      _counter = 1; 
      BadEvent += Handler; 
      BadEvent += Handler; 
      BadEvent += Handler; 
      BadEvent += Handler; 
      BadEvent += Handler; 
      Console.WriteLine("Firing Bad Event. Bad Event is subscribed 5 times from the same Handler."); 
      BadEvent("Bad Event is Invoked."); 

      _counter = 1; 
      GoodEvent -= Handler; 
      Console.WriteLine("GoodEvent is unsubscribed just once. Now fire the Event"); 
      if(GoodEvent!= null) 
      { 
       GoodEvent("Good Event Fired"); 
      } 
      Console.WriteLine("Event is not received to Handler."); 

      BadEvent -= Handler; 
      Console.WriteLine("BadEvent is unsubscribed just once. Now fire the Event"); 
      BadEvent("Good Event Fired"); 
      Console.WriteLine("Event is fired 4 times. If u subscribe good event 5 times then u have to unscribe it for 5 times, otherwise u will be keep informed."); 

      Console.ReadLine(); 
     } 
    } 

发布的岩石。