实现Postsharp EventInterceptionAspect以防止事件处理程序挂起两次 [英] Implement Postsharp EventInterceptionAspect to prevent an event Handler hooked twice

查看:132
本文介绍了实现Postsharp EventInterceptionAspect以防止事件处理程序挂起两次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果您以相同的订阅订阅了.net事件多一次,那么您的订阅方法将被称为与订阅相同的时间。如果您只取消订阅一次,则只会减去一个电话。意思是你必须取消订阅相同的次数,否则你会被通知。有时候你不想这样做。

If you subscribe the .net event with the same subscribe more then once, then your subscribed method will be called the same times as subscribed. And if you unsubscribe just once, then it will be just one minus to the call. Meaning you have to unsubscribe same no of times as subscribed, otherwise u will be keep informed. Somtimes you don't want to do it.

为了防止事件处理程序被挂起两次,我们可以执行如下的事件。

In order to to prevent an event Handler to be hooked twice, we can implement event as following.

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看起来像下面。

Now I would like to implement Postsharp EventInterceptionAspect to make this solution generic, so that I can apply PreventEventHookedTwiceAttribute on every event to save lot of code. But I can't figure out how to check the second part of the following condition in add. I mean foo.GetInvocationList().Contains(value). My PreventEventHookedTwiceAttribute looks like following.

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

我不需要覆盖OnRemoveHandler,因为这里的默认功能是足够的。

I don't need to override OnRemoveHandler, as default functionality is enough here.

推荐答案

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

示例用于显示差异的用法如下:

Example Usage to display the difference is given as below.

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

Postsharp Rocks。

Postsharp Rocks.

这篇关于实现Postsharp EventInterceptionAspect以防止事件处理程序挂起两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆