析构函数通过事件实现

时间:2012-07-06 12:41:33

标签: c# destructor unmanaged

我的框架中有几个对象,即需要提供事件ObjectTerminated。框架的用户可以订阅此事件并清理他正在使用的一些非托管内容。这些对象旨在存在于应用程序的整个生命周期中,而我并不是在控制它们的生命。你可以把它们想象成一群单身人士。

我想写这样的代码:

class SomeWorkflowControlObject
{
     public event EventHandler<> ObjectTerminated;

     ~SomeWorkflowControlObject()
     {
          if (ObjectTerminated != null) ObjectTerminated(this, null);         
     }
}

我不确定,我被允许这样做。这种解决方案可能出现什么问题?

更新

Process.GetCurrentProcess()怎么样。退出了吗?我可以这样使用吗?

2 个答案:

答案 0 :(得分:1)

你不应该这样做。基本上,C#中不存在析构函数。你所写的是终结者,终结者唯一应该做的就是释放非托管资源。

您根本不允许访问任何其他托管对象,因为垃圾收集器可能已经删除了它。我认为你的null检查不足以防范这种情况;该对象引用可能仍然指向您的(事件)委托,即使它已经消失了。

简而言之,不要这样做。

<强>备选方案:

  1. 如果您有Windows窗体应用程序,请订阅Application.ApplicationExit event

  2. 您可能需要考虑实施IDisposable界面,然后执行以下操作:

    public class SomethingVeryLongLived : IDisposable
    {
        …
    }
    
    …
    
    public static void Main()
    {
        using (var sth = new SomethingVeryLongLived(…))
        {
            Application.Run(new SomeForm(…));
        } // <-- at this point, foo.Dispose() is guaranteed to be called.
    }
    

    请注意,即使在使用IDisposable的情况下,在被处理的对象内触发事件可能不是一个好主意/设计,因为不应再访问已处置的对象。

    出于这个原因,我建议你做以下事情:

  3. 使用try…finally

    public static void Main()
    {
        var sth = new SomethingVeryLongLived(…);
        try
        {
            Application.Run(new SomeForm(…));
        }
        finally
        {
            SomethingVeryLongLived.Terminate();
        }
    }
    

    这对我来说似乎是最好的,因为你不是abusing the IDisposable interface,并且很清楚代码的作用......没有隐藏的含义。

答案 1 :(得分:1)

我认为该框架的设计本质上存在缺陷。让我解释一下:

  

1。 [...]我们框架中的几个对象,需要提供事件ObjectTerminated

这没有意义。如果一个对象已被终止,正如事件的名称所暗示的那样,那么我会认为它已经消失了,我无法再访问它。这提出了两个问题:

  • 死亡事件是如何引发事件的?这就像一具尸体从坟墓里与你说话,“我死了。”你真的想要这个吗?

  • 如果事件发件人不再应该在那里,为什么其他人会对这样的事件做出反应?尸体埋葬后有什么可以清理的?

  

2。 我无法控制自己的生活。

控制他们的一生呢?为什么在适当的时候做出或触发必要的清理工作不是他们的责任?让我进一步阐述这一点:

  

3。 [...]可以订阅此活动并清理一些非托管内容[...]

这个非托管的东西在哪里,哪个对象负责处理它?如果它是你自己的对象,那么为什么你的对象不能处理它 - 为什么你想要触发一个事件,以便其他人可以处理这些东西?这就像我执行邻居的垃圾,而不是他自己做的。 (我不是在说那里的老太太。)

如果它看起来像这样,你的课会更有意义:

class SomeWorkflowControlObject : IDisposable
{
     // the following event doesn't make sense, sorry.
     // public event EventHandler<> ObjectTerminated;

     private IntPtr _handleToUnmanagedResource;

     ~SomeWorkflowControlObject()
     {
         Dispose(explicitly: false);         
     }

     public void Dispose()
     {
         Dispose(explicitly: true);
         GC.SuppressFinalize(this);
     }

     protected virtual void Dispose(bool explicitly)
     {
         if (explicitly)
         {
             // free managed resources here; perhaps trigger an event 'Disposing'.
         }
         DisposeUnmanagedResource(_handleToUnmanagedResource);
     }
}

也就是说,它是一些非托管资源的包装器,对于它的处理它自己负责,而没有其他人。因此,不再需要触发事件,以便其他人可以处置非托管资源,无论如何都应隐藏在对象中。