【问题标题】:COM-object was released unintendedlyCOM 对象被意外释放
【发布时间】:2016-05-19 16:35:28
【问题描述】:

我的单元测试有一个辅助类,它共享对内存中 COM 对象的引用:

public class UnitTestGeometryProvider 
{
    public static readonly IGeometry Geometry = Deserialize();
}

几何图形从 Xml 文件反序列化,该文件存储为资源文件并附加到项目中。然后它被包装成一个 COM 对象:

public static IGeometry Deserialize() 
{
    return (IGeometry) new XMLSerializerClass().LoadFromString(myXDoc.OuterXml, null, null);
}

现在我有两个使用存储在此类中的几何的测试方法:

[TestClass()]
public class MyTest
{
    [TestMethod()]
    public void FirstTest()
    {
        var p = UnitTestGeometryProvider.Geometry;
    }   

    [TestMethod()]
    public void SecondTest()
    {
        var p = UnitTestGeometryProvider.Geometry;
    }
}

运行第二个时,我得到一个 COMException:

无法使用已与其底层 RCW 分离的 COM 对象

我想知道为什么要释放对 COM 对象的引用,因为它在 UnitTestGeometryProvider 中标记为 static,而我没有明确释放它。因此,即使 if 实例的 托管资源 会超出范围(这不是静态的),只有当我的所有应用程序终止时测试已完成或更一般,还是我错过了什么?

我正在使用 ArcObjects 和 Visual NUnit。

【问题讨论】:

  • 用 COM 对象初始化 static 字段是一个非常糟糕的主意,而且只能在偶然情况下起作用。您无法保证这会在正确的时间和正确的线程上发生。 lot 很重要,单元线程 COM 对象由特定线程拥有,如果该线程结束,则该对象将像门钉一样死掉。改为使用属性,如果对象仍然为空,则调用 Deserialize()。
  • @HansPassant 好吧,但是这个测试不是在单线程测试之上给出的吗?这里没有涉及多线程,还是static 暗示了它自己?
  • 这样的变量从类型初始化器(又名静态构造器)获取它的值。 .NET 很少保证它们何时或如何运行,只保证它们运行得足够早。您有一个测试运行程序,它可能有自己的想法,它在运行测试之前如何初始化所有内容。如果您想要保证它永远不会出错,那么您就无法获得,那么您有非常​​有力的证据表明它确实出错了。

标签: c# static com arcobjects


【解决方案1】:

由于 Hans Passant 的 cmets,我发现了实际问题。

很明显,Visual-NUnit-Framework 决定为每个测试创建一个单独的线程。因此,每当我创建一个 COM 对象时——不管它是否是静态的——这个对象都存在于这个单一线程上,并且不能在另一个线程中使用。如果线程死了,COM 对象也会执行,或者更准确地说是对它的引用。这会导致 GC 将 COM 对象扔掉,因为 在该线程中不再存在对它的托管引用。

解决方案非常简单:我将静态字段更改为实例成员,并在我的测试类中创建了一个 UnitTestGeometryProvider 类型的实例成员。因此,每次测试都会生成一个新的提供者。
然而这个解决方案很烦人,因为Geometry-property 必须被初始化,因此Deserialize-method 对每个测试都运行,而不是对所有测试只运行一次。

我不知道是否有线程安全的解决方案,在初始化 COM 对象的第一个线程死亡时不终止对 COM 对象的引用。

【讨论】:

  • 我不确定它是否对你有用,但我发现在处理 COM 和线程时使用StaThreadSyncronizer 很方便,请参阅Understanding SynchronizationContext 和后续文章。这允许与 COM 相关的所有内容都在同一个线程中执行。但我从来不需要在单元测试中使用它。
猜你喜欢
  • 2015-09-25
  • 2012-09-17
  • 2015-07-09
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 2012-03-05
  • 2014-02-14
相关资源
最近更新 更多