【问题标题】:Implement Postsharp EventInterceptionAspect to prevent an event Handler hooked twice实现 Postsharp EventInterceptionAspect 以防止事件处理程序被钩住两次
【发布时间】:2012-04-28 14:44:03
【问题描述】:

如果您使用相同的订阅多次订阅 .net 事件,那么您订阅的方法将被调用与订阅相同的时间。而且,如果您只取消订阅一次,那么通话只会减一分。这意味着您必须取消订阅的次数与订阅的次数相同,否则您将收到通知。有时你不想这样做。

为了防止一个事件处理程序被钩住两次,我们可以如下实现事件。

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

现在我想实现 Postsharp EventInterceptionAspect 以使这个解决方案通用,这样我就可以在每个事件上应用 PreventEventHookedTwiceAttribute 以节省大量代码。但我不知道如何在 add.xml 中检查以下条件的第二部分。我的意思是 foo.GetInvocationList().Contains(value)。我的 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,因为这里的默认功能就足够了。

【问题讨论】:

  • 您不希望同一个订阅者订阅两次,还是只想要一个订阅期?
  • @DustinDavis:感谢您的提问。我想防止同一个订阅者订阅两次。像这个例子: void EventHandler(){.....} Main() { someClass.SomeEvent += EventHandler; someClass.SomeEvent += EventHandler;如果我使用普通事件,那么 EventHandler 方法将被调用两次。但是如果我使用 Foo 中实现的模式,那么它只会被调用一次。
  • @DustinDavis:我解决了这个问题。请看我的回答。

标签: c# event-handling postsharp


【解决方案1】:

这个类可以解决问题。

[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();
        }
    }

后锐岩石。

【讨论】:

    猜你喜欢
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 2011-07-08
    • 2023-03-21
    • 1970-01-01
    • 2010-09-28
    • 1970-01-01
    • 2013-12-15
    相关资源
    最近更新 更多