时间:2010-07-26 17:28:26

标签: c# .net vb.net finalizer

4 个答案:

答案 0 :(得分:3)

答案 1 :(得分:0)

让我确定我理解 - 您是否担心仍然订阅收集的活动发布者的活动订阅者的泄密?

如果是这种情况,那么我认为你不必担心它。

这就是我的意思,假设“前”对象是事件订阅者而“后者”对象是事件发布者(引发事件):

订阅者(前者)“订阅”的唯一原因是您创建了一个委托对象并将该委托传递给发布者(“后者”)。

如果查看委托成员,它会引用订阅者对象以及将要执行的订阅者上的方法。所以有一个参考链看起来像这样:publisher - >代表 - > subscriber(发布者引用委托,引用订阅者)。这是一个单向链 - 订户没有对委托的引用。

因此,保留委托的唯一根目录是发布者(“后者”)。当后者有资格获得GC时,代表也是如此。除非您的订阅者在取消订阅时需要采取某些特殊操作,否则当代表被收集时,它们将有效地取消订阅 - 没有泄漏。

修改

基于supercat的评论,听起来问题是发布者保持订户活着。

如果这是问题,那么终结者将无法帮助您。原因:您的发布商对您的订阅者(通过代理人)提供了真实的真实参考,并且发布者已植根(否则它将符合GC的条件),因此您的订阅者已植根,并且无法完成最终确定或GC。

如果您在发布商保持订户活跃方面遇到问题,我建议您搜索弱参考事件。以下是一些可以帮助您入门的链接:http://www.codeproject.com/KB/cs/WeakEvents.aspx http://www.codeproject.com/KB/architecture/observable_property_patte.aspx

我也必须处理这一次。大多数有效模式涉及更改发布者,以便它对代表持有弱引用。然后你有一个新的问题 - 委托没有根,你就会以某种方式让它保持活力。上面的文章可能会做那样的事情。有些技术使用反射。

我曾经使用过一种不依赖于反射的技术。但是,它要求您能够对发布者和订阅者中的代码进行更改。如果您想查看该解决方案的示例,请与我们联系。

答案 2 :(得分:0)

我打算将对象称为“发布者”和“订阅者”,并重申我对该问题的理解:

在C#中,发布者将(有效地)保留对订阅者的引用,从而防止订阅者被垃圾回收。我该怎么做才能在不明确管理订阅的情况下对订阅者对象进行垃圾回收?

首先,我建议先做我能做的一切以避免这种情况。现在,我将继续前进并假设你有,考虑到你发布的问题无论如何=)

接下来,我建议挂钩添加和删除发布者事件的访问者并使用WeakReferences集合。然后,只要调用事件,您就可以自动取消挂起这些订阅。这是一个非常粗糙,未经测试的示例:

private List<WeakReference> _eventRefs = new List<WeakReference>();

public event EventHandler SomeEvent
{
    add
    {
        _eventRefs.Add(new WeakReference(value));
    }
    remove
    {
        for (int i = 0; i < _eventRefs; i++)
        {
            var wRef = _eventRefs[i];
            if (!wRef.IsAlive)
            {
                _eventRefs.RemoveAt(i);
                i--;
                continue;
            }

            var handler = wRef.Target as EventHandler;
            if (object.ReferenceEquals(handler, value))
            {
                _eventRefs.RemoveAt(i);
                i--;
                continue;
            }
        }
    }
}

答案 3 :(得分:0)

让我们再试一次。您可以将您的事件处理程序添加到您的发布者,如下所示:

var pub = new Publisher();
var sub = new Subscriber();
var ref = new WeakReference(sub);

EventHandler handler = null; // gotta do this for self-referencing anonymous delegate

handler = (o,e) =>
{
    if(!ref.IsAlive)
    {
        pub.SomeEvent -= handler; // note the self-reference here, see comment above
        return;
    }


    ((Subscriber)ref.Target).DoHandleEvent();
};

pub.SomeEvent += handler;

这样,您的代理人不会直接引用订阅者,并且无论何时收集订阅者都会自动取消挂钩。您可以将其实现为Subscriber类的私有静态成员(出于封装的目的),只需确保它是静态的,以防止无意中持有对“this”对象的直接引用。