【问题标题】:Copy invocation-list from one delegate to another将调用列表从一个委托复制到另一委托
【发布时间】:2010-11-30 16:16:11
【问题描述】:

我正在使用表达式构建器模式来构建一个对象。表达式构建器在对象上配置的其中一件事是事件处理程序。下面是一些演示伪代码:

public class TargetObject
    {
        public event Action SomeEvent;
    }

    public class ObjectBuilder
    {
        private Action handler;

        public TargetObject GetObject()
        {
            TargetObject target = new TargetObject();
            target.SomeEvent += handler;

            return target;
        }

        public ObjectBuilder AddHandler(Action handler)
        {
            this.handler += handler;
            return this;
        }
    }

我想要的是,而不是写:

this.handler += handler;

将ObjectBuilder中“handler”成员封装的调用列表传递给target中的“SomeEvent”。否则,ObjectBuilder 将不会被垃圾收集,因为我的 TargetObject 的“SomeEvent”将持有对 ObjectBuilder 的“处理程序”的引用。

这可能吗?

编辑: 根据要求,这里是一些使用这些类的示例代码:

class Program
    {
        static void Main(string[] args)
        {
            TargetObject target = new ObjectBuilder()
                .AddHandler(DoSomething)
                .GetObject();
        }

        private static void DoSomething()
        {
        }
    }

【问题讨论】:

  • 这两个对象是同一类型吗?
  • 委托是不可变的引用类型。返回的TargetObject 将不会阻止创建它的ObjectBuilder 实例被GCed。 handler 字段保存对堆上某个委托实例 elsewhere 的 reference。当您执行target.SomeEvent += handler; 时,此引用被复制 换句话说,target 根本不知道此ObjectBuilder,并且不会直接或通过它的(大概)其事件处理程序的委托字段。
  • 不,这是不正确的。委托是内存泄漏的常见来源。正如您自己写的那样,处理程序字段包含对堆上委托的引用。在这种情况下,引用的委托是 ObjectBuilder 类的成员,这意味着只要存在此引用,ObjectBuilder 就不会被 GC。
  • @joniba:“委托是内存泄漏的常见来源”,因为委托需要在调用代码时访问代码。这就是为什么它有一个目标字段。这就是为什么委托人需要在某处持有参考资料的原因。但是,除非您传递给 AddHandler 的处理程序是在 ObjectBuilder 中定义的,否则目标对象不包含 Object Builder。
  • @joniba:请在调用 AddHandler 和 GetObject 的位置发布代码。我编写了一个简单的测试应用程序,但无法重现任何泄漏。

标签: .net events delegates


【解决方案1】:

您确定 ObjectBuilder 没有经过 GC 处理,因为 TargetObject 实例持有其“处理程序”字段吗? delegate 是不可变的,this.handler += handler 会创建一个新的 Action 实例。

【讨论】:

  • 请查看我对 Ani 评论的最后评论。你是对的,创建了一个新的委托实例,但是这个新实例引用了 ObjectBuilder 实例的一个成员。
  • @joniba:我编写了一个测试应用程序,但使用 Memory Profiler 找不到任何泄漏。
猜你喜欢
  • 1970-01-01
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 2015-12-08
  • 1970-01-01
相关资源
最近更新 更多