【发布时间】: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 的位置发布代码。我编写了一个简单的测试应用程序,但无法重现任何泄漏。