使托管对象真正可删除

时间:2016-06-28 07:55:14

标签: c# idisposable weak-references

背景

我周六试着问this问题,但没有真正的结论,所以我想我会尝试以不同的方式提问,因为这个问题让我头痛不已。

我的应用程序是一个嵌入式HMI设计工具。这允许用户(内部开发人员)可视化地设计嵌入式HMI的外观,然后通过单击按钮生成C代码。现在大部分都有效。

该工具的主要功能之一是允许用户创建新的屏幕(然后可以在其上放置控件)。在我的应用程序中,屏幕&#39;是一个对象。添加新屏幕后,会将其放置在List<Screen>中,稍后将用于生成C代码。

该屏幕的一个属性是private Screen nextScreen,它是对另一个屏幕对象的引用,它指示按下导航按钮时下一个要显示的屏幕。这一切都很有效。

问题:

但是,在使用该工具生成代码时,我们发现了一个问题。创建了2个屏幕,第一个屏幕的nextScreen属性设置为第2个。稍后我们决定第二个屏幕是错误的,因此它被删除并创建了一个新屏幕。但是他们忘了将第一个屏幕nextScreen属性设置为这个新屏幕,因此它仍然引用原始屏幕,视觉上已被删除。

生成代码时,生成的C代码无法编译,因为第一个屏幕引用的屏幕在生成的C环境中不存在。

问题:

所以我的问题是如何才能最好地实现一种删除方式,以确保任何引用某个对象的内容被删除&#39;知道它并将该属性设置为null?

到目前为止的想法:

1)我尝试过制作&#39; nextScreen&#39;作为WeakReference的属性确实有效,但这意味着每次删除时我都必须手动调用GC.Collect()...根据我的理解不理想! (我的尝试这个例子可以在这篇文章顶部的链接中找到)

2)删除后,我可以检查所有对象以获取对被删除对象的引用,并将其设置为null。然而,我上面描述的只是组成HMI的众多对象之一,其中大多数对其他对象有一个或多个引用。所以这可能很慢,在我看来似乎并不合适。

3)也许使用IDisposable ???但根据我的理解,这是针对非托管代码的!

我想要阅读的任何想法或领域都会很棒,因为我现在正在把头发拉出来......不是说我有太多的东西!!!

3 个答案:

答案 0 :(得分:0)

我认为你可以使用ObjectPool模式来创建和删除对象以及它上面的一些Wrapper来控制它们的实时时间

答案 1 :(得分:0)

GC的一个基本设计要求是,如果有任何代码可能遇到对象的引用,该对象将继续存在。没有办法去除&#34;删除&#34;一个对象,以致对它的引用将变为无效。但是,你可以做两件事:

  1. 让您的类包含一个字段,该字段指示它是否已失效,并且具有接收或遵循对类实例的引用的代码,检查该字段以确保实例仍然有效。如果代码在实例中设置该字段,则对它的任何引用将不再是对有效实例的引用,而是(根据定义)将成为对无效实例的引用。

  2. 如果您为对象创建WeakReference,那么当GC检测到没有非弱引用时,Target的{​​{1}}属性将变为WeakReference到目标存在(如果对非空目标的引用被复制到另一个变量,该变量将使目标保持活动,即使弱引用是宇宙中唯一引用目标的东西)。强制完整的垃圾收集周期通常会立即使对任何在任何地方都没有被强烈引用的对象的弱引用无效,但会代表某些滥用GC系统的行为。

  3. 实施&#34;查找所有使用的对象&#34;例程,它计算它运行了多少次,并在每个类实例中有一个字段,该例程将存储其计数器。应该考虑的任何对象&#34;使用&#34;将保持值&#34;找到所有使用过的对象&#34;常规计数器最后一次运行。这有点像GC对它所知道的对象所做的那样,但是如果你自己这样做,你可以决定哪些形式的引用应该对于一个对象是合理的&#34;使用&#34;。

答案 2 :(得分:0)

您可以创建一个名为Deletable<T>的新泛型类来包装您的对象。它与Nullable<T>的工作方式类似,因为它包含一个保存原始值的T类型的属性。它需要一个只读bool属性IsDeleted来指示是否已删除包装的值,以及Delete方法将包装的值清空,并设置IsDeleted标志。

使用Screen个对象的所有内容都会切换为Deletable<Screen>。删除屏幕后,在包装器上调用Delete。任何关注屏幕是否被删除的代码都可以在使用scr.IsDeleted之前检查scr.Value

这将允许垃圾收集清理任何大型对象,同时在其位置留下一个漂亮的小“标志”值,您可以使用它来检查是否已删除真实对象。