【问题标题】:Preventing same Event handler assignment multiple times防止多次分配相同的事件处理程序
【发布时间】:2010-09-28 19:36:53
【问题描述】:

如果我在运行时分配一个事件处理程序,并且它位于可以多次调用的位置,那么建议的做法是什么,以防止将同一处理程序多次分配给同一事件。

object.Event += MyFunction

将它添加到将被多次调用的位置将执行处理程序“n”次(当然)。

在尝试通过添加之前,我已经删除了任何以前的处理程序

object.Event -= MyFunction; 

object.Event += MyFunction;

这可行,但似乎以某种方式关闭。有关正确处理此方案的任何建议;)。

【问题讨论】:

标签: c# events


【解决方案1】:

我倾向于在执行一次的路径中添加事件处理程序,例如在构造函数中。

【讨论】:

    【解决方案2】:

    Baget 关于使用显式实现的事件是正确的(尽管其中混合了显式接口实现和完整的事件语法)。您可能可以逃脱惩罚:

    private EventHandler foo;
    
    public event EventHandler Foo
    {
        add
        {
            // First try to remove the handler, then re-add it
            foo -= value;
            foo += value;
        }
        remove
        {
            foo -= value;
        }
    }
    

    如果您添加或删除多播委托,这可能会出现一些奇怪的边缘情况,但这不太可能。它还需要仔细记录,因为这不是事件正常工作的方式。

    【讨论】:

    • 为避免编译器错误,在触发事件时使用事件的“私有”名称。 “富”与“富”
    【解决方案3】:

    您可以实现自己的委托存储,并在将它们添加到事件时检查唯一性。有关示例,请参见下面的 EventOwner2 类。我不知道这在性能方面的表现如何,但再说一遍,这并不总是一个问题。

    using System;
    using System.Collections.Generic;
    
    namespace EventExperiment
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEventOwner e=new EventOwner2();
                Subscriber s=new Subscriber(e);
                e.RaiseSome();
                Console.ReadKey();
            }
        }
    
        /// <summary>
        /// A consumer class, subscribing twice to the event in it's constructor.
        /// </summary>
        public class Subscriber
        {
            public Subscriber(IEventOwner eventOwner)
            {
                eventOwner.SomeEvent += eventOwner_SomeEvent;
                eventOwner.SomeEvent += eventOwner_SomeEvent;
            }
    
            void eventOwner_SomeEvent(object sender, EventArgs e)
            {
                Console.WriteLine(DateTimeOffset.Now);
            }
    
        }
    
        /// <summary>
        /// This interface is not essensial to this point. it is just added for conveniance.
        /// </summary>
        public interface IEventOwner
        {
            event EventHandler<EventArgs> SomeEvent;
            void RaiseSome();
        }
    
        /// <summary>
        /// A traditional event. This is raised for each subscription.
        /// </summary>
        public class EventOwner1 : IEventOwner
        {
            public event EventHandler<EventArgs> SomeEvent = delegate { };
            public void RaiseSome()
            {
                SomeEvent(this,new EventArgs());
            }
        }
        /// <summary>
        /// A custom event. This is raised only once for each subscriber.
        /// </summary>
        public class EventOwner2 : IEventOwner
        {
            private readonly List<EventHandler<EventArgs>> handlers=new List<EventHandler<EventArgs>>();
            public event EventHandler<EventArgs> SomeEvent
            {
                add
                {
                    lock (handlers)
                        if (handlers!=null&&!handlers.Contains(value))
                        {
                            handlers.Add(value);
                        }
                }
                remove
                {
                    handlers.Remove(value);
                }
            }
            public void RaiseSome()
            {
                EventArgs args=new EventArgs();
                lock(handlers)
                foreach (EventHandler<EventArgs> handler in handlers)
                {
                    handler(this,args);
                }
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      'object'的访问修饰符是什么?

      如果它是私有的,您只需要担心包含对象设置事件处理程序。 如果它是内部的,您只需要担心包含程序集设置事件处理程序。 如果它是公开的,那么它就是完全开放的。

      如果“object”可以在包含的类上设为私有,您可以通过控制本地类中的事件处理程序分配来提高检查效率。

      如果需要“内部”或“公共”和唯一性,请使用隐藏“对象”的包装类,而是公开一个用于分配事件处理程序的方法,并在其后进行检查以确保唯一性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-21
        • 2016-10-01
        • 2016-12-09
        • 1970-01-01
        • 1970-01-01
        • 2021-04-25
        • 2021-02-12
        • 1970-01-01
        相关资源
        最近更新 更多