1

同じサブスクライブで.netイベントを複数回サブスクライブすると、サブスクライブされたメソッドはサブスクライブと同じ回数呼び出されます。そして、あなたが一度だけ退会するならば、それは電話へのたった1つのマイナスになります。つまり、サブスクライブした回数と同じ回数、サブスクライブを解除する必要があります。そうしないと、uに通知され続けます。時々あなたはそれをしたくない。

イベントハンドラーが2回フックされるのを防ぐために、次のようにイベントを実装できます。

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

ここで、Postsharp EventInterceptionAspectを実装してこのソリューションを汎用化し、PreventEventHookedTwiceAttributeすべてのイベントに適用して多くのコードを節約できるようにします。しかし、次の条件の2番目の部分を追加で確認する方法がわかりません。私は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をオーバーライドする必要はありません。

4

1 に答える 1

2

このクラスはトリックを行います。

[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-20T16:17:55.140 に答える