【问题标题】:C# listening to 3rd party long living event using weak referenceC# 使用弱引用监听 3rd 方长寿事件
【发布时间】:2013-10-07 14:33:44
【问题描述】:

我正在附加到第 3 方,长期存在的 Deleted 事件发布者,由于事件处理程序,它最终使我可能短暂存在的对象保持活动状态。 Deleted 事件很可能永远不会触发,如果是,我只需要处理。取消订阅 Deleted 事件的位置并不明显,因此我希望对它进行弱引用,以便我的对象可以被 GC'd。

我见过很多非常精细的方法来创建弱事件处理程序,但是下面的 sn-p 似乎可以解决问题,至少在提供的测试 sn-p 中是这样。这只是疯了还是可以工作?

http://diditwith.net/CommentView,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx 在“A First Stab”下说类似的 sn-p “(...) 不够健壮,无法与事件 (...) 一起使用”,为什么不呢?)

public static class WeakEvent
{
    private class WeakEventHolder<TArgs> where TArgs : EventArgs
    {
        private readonly WeakReference _handler;

        public WeakEventHolder(Action<object, TArgs> handler)
        {
            _handler = new WeakReference(handler);
        }

        public void Handle(object sender, TArgs args)
        {
            Action<object, TArgs> handler = (Action<object, TArgs>)_handler.Target;
            if (handler != null)
                handler(sender, args);
        }
    }

    public static EventHandler MakeHandler(Action<object, EventArgs> handler)
    {
        return new WeakEventHolder<EventArgs>(handler).Handle;
    }
}

测试类

[TestFixture]
public class Tests
{
    public class Publisher
    {
        public EventHandler Event;

        public void Raise()
        {
            if (Event != null)
                Event(this, EventArgs.Empty);
        }
    }

    public class Target
    {
        public Target(Publisher publisher)
        {
            publisher.Event += WeakEvent.MakeHandler(HandleEvent);
        }

        public void HandleEvent(object sender, EventArgs args)
        {
            System.Diagnostics.Trace.WriteLine("HandleEvent");
        }
    }

    [Test]
    public void Test()
    {
        Publisher publisher = new Publisher();
        WeakReference wref = new WeakReference(new Target(publisher));
        GC.Collect();

        publisher.Raise();

        Assert.False(wref.IsAlive);
    }
}

【问题讨论】:

    标签: c# weak-events


    【解决方案1】:

    因为Action&lt;object, TArgs&gt; handler 可能在它的目标之前收集了垃圾。这是一个暴露问题的单元测试:

    public class Bar
    {
        public void Foo(object sender, EventArgs args)
        {
        }
    }
    
    [Test]
    public void ActionIsNotGCedBeforeTarget()
    {
        Bar bar = new Bar();
        Action<object, EventArgs> action = bar.Foo;
        WeakReference weakRef = new WeakReference(action);
        action = null;
        GC.Collect();
    
        Assert.IsTrue(weakRef.IsAlive); // Will be false
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 2017-04-16
      • 2018-04-18
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      相关资源
      最近更新 更多