我的框架中有几个对象,即需要提供事件ObjectTerminated。框架的用户可以订阅此事件并清理他正在使用的一些非托管内容。这些对象旨在存在于应用程序的整个生命周期中,而我并不是在控制它们的生命。你可以把它们想象成一群单身人士。
我想写这样的代码:
class SomeWorkflowControlObject
{
public event EventHandler<> ObjectTerminated;
~SomeWorkflowControlObject()
{
if (ObjectTerminated != null) ObjectTerminated(this, null);
}
}
我不确定,我被允许这样做。这种解决方案可能出现什么问题?
更新
Process.GetCurrentProcess()怎么样。退出了吗?我可以这样使用吗?
答案 0 :(得分:1)
你不应该这样做。基本上,C#中不存在析构函数。你所写的是终结者,终结者唯一应该做的就是释放非托管资源。
您根本不允许访问任何其他托管对象,因为垃圾收集器可能已经删除了它。我认为你的null
检查不足以防范这种情况;该对象引用可能仍然指向您的(事件)委托,即使它已经消失了。
简而言之,不要这样做。
<强>备选方案:强>
如果您有Windows窗体应用程序,请订阅Application.ApplicationExit
event。
您可能需要考虑实施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
的情况下,在被处理的对象内触发事件可能不是一个好主意/设计,因为不应再访问已处置的对象。
出于这个原因,我建议你做以下事情:
使用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);
}
}
也就是说,它是一些非托管资源的包装器,对于它的处理它自己负责,而没有其他人。因此,不再需要触发事件,以便其他人可以处置非托管资源,无论如何都应隐藏在对象中。