2011-01-08 89 views
3

有没有办法来检测一个对象是否调用了GC.SuppressFinalize?我可以检测一个对象是否调用了GC.SuppressFinalize?

我有一个对象,它看起来像这样(省略掉了清晰全面的Dispose模式):

public class ResourceWrapper { 
    private readonly bool _ownsResource; 
    private readonly UnmanagedResource _resource; 

    public ResourceWrapper(UnmanagedResource resource, bool ownsResource) { 
     _resource = resource; 
     _ownsResource = ownsResource; 
     if (!ownsResource) 
      GC.SuppressFinalize(this); 
    } 
    ~ResourceWrapper() { 
     if (_ownsResource) 
      // clean up the unmanaged resource 
    } 
} 

如果ownsResource构造函数的参数是false,那么将终结无关 - 这样这似乎是合理的(如果有点古怪)从构造函数中调用GC.SuppressFinalize。但是,因为这种行为很古怪,所以我很想在XML文档注释中记下它......如果我试图对它进行评论,那么我应该为它写一个单元测试。

不过,虽然System.GC有方法来设置对象的finalizability(SuppressFinalizeReRegisterForFinalize),我看不出有什么方法来得到对象的finalizability。有没有什么方法可以查询GC.SuppressFinalize是否在给定的实例上被调用,缺少购买Typemock或写我自己的CLR主机?

回答

3

如果你想确认如果你的对象不拥有资源,最终确定已被抑制,也许你可以让终结器声明它拥有资源?测试必须执行GC.Collect和GC.WaitForPendingFinalizers,但生产代码除了assert(可从生产版本中省略)之外不会有任何额外的内容。断言的一个小警告:如果创建对象的线程在创建对象和设置所有权状态之间死亡,则终结器可能不适当地运行。

上面已经说过,我想知道是否最好有一个抽象的ResourceWrapper类型,带有单独的子类型OwnedResourceWrapper和SharedResourceWrapper,它拥有或不拥有有问题的资源。然后,不拥有资源的子类型首先不需要有终结器。请注意,SharedResourceWrapper可能会将IDisposable作为无操作来实现。

4

这是不可能的,GC只是不提供此信息。很好的理由,它不只是对象可以进入的两个状态。它也可能已经在最终确定队列中,或者它可能已经完成。

自定义CLR主机不会帮助你,主机接口不提供任何挂钩到gc。你可以检查SuppressFinalize是否已经被调用,只要在终结器中检查它就可以了。记录(快速)。你不能证明相反。

Fwiw,.NET框架类不这样做,他们只是让终结器运行。

+0

一些BCL类实际上是从其构造函数中执行SuppressFinalize,例如, SqlConnection(尽管我没有看到任何有条件的)。 – 2011-01-08 16:42:38

2

这可能有帮助(reductio absurdum)。一个窍门是在终结器中做一些日志(这可能是一个静态状态),如果有人不在,他已经打电话给压制最终确定,但你仍然无法确定何时。

这是工作,如果你是类型的作者。

+0

我想过那个。这也需要从我的测试中调用GC.Collect和GC.WaitForPendingFinalizers,尽管这是可行的。但我讨厌让生产代码做额外的工作,仅用于测试。 – 2011-01-08 16:44:42

+0

我不推荐它,但仍然是一个解决方案。也许你会从别人那里找到更可靠的解决方案。 – Xaqron 2011-01-08 16:46:29

相关问题