新事件的EventHandler语法差异(非泛型)

时间:2013-08-22 18:43:22

标签: c# events

我正试图解决这个问题。下面的代码最终只计算SubscribersClass类型的垃圾收集对象的数量。当代码如图所示运行时,我得到SubscribersClass.Count值为0.当我在EventsClass中注释掉第一行并取消注释该类的其余部分时,SubscribersClass.Count的值为10.

我唯一能想到的是因为EventsClass EventHandler出现了问题(如图所示),所以实际上并没有创建SubscribersClass的实例。

希望有人能帮我理解究竟发生了什么。

这是学术性的,没有实际价值。只是想弄清楚,但到目前为止只能设法获得GoogleBlisters。

namespace understandingEvents
{
    public class EventsClass
    {
        public event EventHandler SomeEvent;  // if this is commented out and
                                              // remainder of class is uncommented
                                              // it works fine
        /*
        public event EventHandler SomeEvent
        {
             add
             {
                 Console.WriteLine("An event has been added");
             }
             remove
             {
                 Console.WriteLine("An event has been removed");
             }
         }
         */
    }

    public class SubscribersClass
    {
        static int count = 0;

        static public int Count
        {
            get { return count; }
        }

        public  SubscribersClass (EventsClass eventPublisher)
        {
            eventPublisher.SomeEvent += new EventHandler(Subscriber_SomeEvent);
        }

        ~SubscribersClass()
        {
            Interlocked.Increment(ref count);
        }

        public void Subscriber_SomeEvent(object sender, EventArgs e)
        {
            Console.WriteLine("This is an event");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            EventsClass publisher = new EventsClass();
            for (int i = 0; i < 10; i++)
            {
                SubscribersClass subscriber = new SubscribersClass(publisher);
                subscriber = null;
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine(SubscribersClass.Count.ToString());
        }
    }
}

3 个答案:

答案 0 :(得分:3)

当您使用标准的,编译器实现的事件(public event EventHandler SomeEvent;)时,订阅该事件会导致在该事件中保留对订阅者的引用,因为该委托引用了{{1的实例方法}}

这意味着SubscribersClass仍然保留对每个publisher的引用,因此它们永远不会被释放。

当您编写自己的subscriberadd处理程序时,您实际上并未使用该委托,因此会忽略该委托(您会发现提升该事件没有任何效果且不是'在这种情况下由订户处理),这也意味着那些引用没有被保留,因此remove呼叫可以“清理”订户。这会导致计数增加。

答案 1 :(得分:2)

订阅活动时,发布商将保留对订阅者的引用。这是允许发布者在事件发生时调用所有订阅事件的方法的原因。

要解决您的问题,只需在销毁对象之前删除订阅。 (您需要存储对事件发布者的引用)。您可以通过手动调用某些Unsubscribe方法或(更好)实现IDisposable并在Dispose()中取消订阅来完成此操作。

public  SubscribersClass (EventsClass eventPublisher)
    {
        m_eventPublisher = eventPublisher;
        eventPublisher.SomeEvent += new EventHandler(Subscriber_SomeEvent);
    }


public override void Dispose()
{
        m_eventPublisher.SomeEvent -= Subscriber_SomeEvent;
}

答案 2 :(得分:0)

您没有删除测试代码中的事件susbscribers,因此未收集SubscribersClass个实例。

注释掉的代码根本不会添加侦听器,因此SubscribersClass的所有实例都会在创建后立即为GC准备好。

请注意,由于所有变量的生命周期延长,代码(如果正确修复)在DEBUG构建中的行为也会有所不同。考虑将所有有趣的代码放在函数中并在其外部触发GC。

相关问题