执行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,因为默认功能就够了。
答
这个班有诀窍。
[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();
}
}
发布的岩石。
你不希望同一个订户两次订阅两次,或者你只想要一个订户周期? – 2012-04-17 15:17:21
@DustinDavis:谢谢你的提问。我想阻止同一订阅者订阅两次。像这样: void EventHandler(){.....} Main() { \t someClass.SomeEvent + = EventHandler; \t someClass.SomeEvent + = EventHandler; } 如果我使用正常事件,那么EventHandler方法将被调用两次。但是如果我使用在Foo中实现的模式,那么它只会被调用一次。 – Saghar 2012-04-18 14:28:48
@DustinDavis:我解决了这个问题。请看我的答案。 – Saghar 2012-04-20 16:19:13