C#:如何处理包含的对象作为其结果';什么是自己的事?
背景: 我有一个主对象,它位于我的应用程序的UI线程上。这个长期存在的父对象/容器对象包含一个子对象作为内部多线程的私有成员 基于从子对象/包含对象发布的某个事件,我希望父对象只需C#:如何处理包含的对象作为其结果';什么是自己的事?,c#,multithreading,events,c#-4.0,idisposable,C#,Multithreading,Events,C# 4.0,Idisposable,背景: 我有一个主对象,它位于我的应用程序的UI线程上。这个长期存在的父对象/容器对象包含一个子对象作为内部多线程的私有成员 基于从子对象/包含对象发布的某个事件,我希望父对象只需Dispose()子对象并重新创建它 包含的对象拥有一些非托管资源和一些大型托管内存缓冲区 我可以在顶层对象上创建一个事件处理程序来执行此操作,但这意味着将要释放的对象将位于将要替换它的方法调用的调用堆栈中。(!) 这是因为事件处理程序委托将由子对象自身线程上的一个状态处理函数调用 这似乎……错了。没有 特别是,子对象
Dispose()
子对象并重新创建它
包含的对象拥有一些非托管资源和一些大型托管内存缓冲区
我可以在顶层对象上创建一个事件处理程序来执行此操作,但这意味着将要释放的对象将位于将要替换它的方法调用的调用堆栈中。(!)
这是因为事件处理程序委托将由子对象自身线程上的一个状态处理函数调用
这似乎……错了。没有
特别是,子对象的FireAnEvent()
方法将在处理委托调用后恢复执行,但现在执行将在已“释放”对象的上下文中恢复
凭直觉,我看不出这会带来好的结果
问题:
是否存在一个已建立的C#模式来销毁一个包含的对象作为其自身事件的结果
或者,有没有GC魔法让这样一个简单的事件处理程序变得足够好
或者,我缺少一些关键的理解吗?调用
IDisposable.Dispose()
不会向.NET framework发出任何特殊的信号。您只需要删除对要删除的对象的任何引用。一旦完成此操作并且对象脱离调用堆栈,它将成为垃圾收集的候选对象
请注意,对象不一定会立即被垃圾收集,甚至在下次GC运行时也不会被垃圾收集;这只是一种假设的可能性
IDisposable
的唯一目的是提供一种标准方法,用于请求对象清理自身并释放资源。您可以随时保留对“disposed”对象的引用,这将阻止GC收集该对象IDisposable.Dispose()
只是另一种方法;从技术上讲,你可以让它做任何你想做的事情
这个问题有一个非常详细的答案,可能会帮助您进一步理解
IDisposable
:如前所述,IDisposable
对象并没有什么神奇之处。它只允许您使用使用速记,这只是对以下内容的速记:
try { // code in the using block }
catch{}
finally{
disposableObject.Dispose()
}
你有没有考虑过将第三种类型的对象合并到混合中?被包含的对象意识到其容器是不明智的。
大致上这就是您的工作流程:
包含的对象决定应重新启动它
包含的对象释放资源
包含对象写入第三个对象(不是包含对象)上的队列
当您认为应该创建新的包含对象并重新实例化对象时,包含对象将访问队列。或者,添加到队列会向容器引发事件以清空容器
第三个对象可能看起来毫无意义,但如果您决定进行重构,它将使您的生活变得更加轻松。为通知目的订阅事件的对象应该随时准备接收通知,即使它们已被处置。通知的目的是告诉对象做它需要做的任何事情来响应已经发生的事情。如果一个对象在响应通知时不能做任何有用的事情,它就不应该做任何事情
此外,Dispose
的目的不是“销毁”对象及其包含的资源,而是将其从对外部对象可能承担的任何义务中释放出来,并允许其将任何外部实体从对其可能承担的任何义务中释放出来。在许多情况下,一个对象一旦释放了向其承诺的外部实体的服务,它将是无用的,因此,不能期望已处置的对象是有用的;如果在Disposed
之后调用的方法由于必要的外部实体已被释放而无法满足其职责,那么它应该抛出ObjectDisposedException
,而不是以其他方式失败
将这些观察结果放在一起,虽然处置对象上的许多方法都应该抛出ObjectDisposedException
,但通知事件处理程序方法不应该抛出,因为它们指示对象“在发生了某些事情的情况下,尽你所能满足你的义务”。如果某个对象已被处置,则该对象没有义务。因此,被处置不会阻止对象满足事件处理程序契约;相反,它允许对象通过静默(“成功地”)不做任何事情来满足约定。与长寿命父对象相比,子对象的寿命短吗?父类和子类是指类和子类,还是容器和包含的?可能是您需要创建一些线程控制逻辑,一旦您的子类检测到需要终止线程,这些逻辑将终止线程。或者将您的孩子转移到单独的流程中。然后,终止这个子进程将意味着销毁该进程中的所有线程,只要您将它们标记为background
。这是主观的。如果有一个C字形模式,那么考虑到微软组件中没有一个“你只能调用Debug()),如果这个和那个事件没有被激活“手册页”。这样做是不明智的,你通常不能确定程序员是否考虑过这种可能性。当然,这不是你的问题,你可以很容易地测试它,修复也很容易。如果你讨厌这个想法,那么考虑另一种选择,你可以总是开始调用()以获得稍后执行的处理调用。精确的