我能在我的终结器中引用/使用COM对象吗?

4
我有一个使用 tlbimp.exe 创建的 COM 类型和一个包装此对象的 C# 类。 我想在我的 C# 包装器的终结器中执行一些清理工作。 遵循 这里 的指南,我可能会编写类似以下内容的代码:
public class MyClass : IDisposable
{
    private IMyComObject comObject;

    public MyClass()
    {
        comObject = new MyComObject();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~MyClass()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        // Be tollerant of partially constructed instances
        if (comObject != null)
        {
            comObject.Cleanup();
            // Account for object being disposed twice
            comObject = null;
        }
    }

    // Other bits go here...
}

我知道finalizer的执行顺序是不确定的,所以我不应该尝试使用任何实现finalizer的对象,但据我所知,tlbimp生成的COM类型不实现finalizer,因此上述问题应该没有问题。
然而,我没有找到任何官方文档来证明这一点,所以我的问题是:在finalizer中引用和使用COM对象是否安全?

你有尝试在Dispose方法的开头调用GC吗? - Ventsyslav Raikov
它们确实实现了一个 finalizer,这就是 COM 对象被释放的方式。因此,不,这并不安全。 - Hans Passant
@HansPassant 我曾经也这么想,但我找不到任何说明文件来证明这一点,而且我在反汇编中也看不到终结器。 - Justin
终结器存在于CLR创建的RCW上。你看不到它。 - Hans Passant
附注:在终结器代码中引发的任何未处理异常都将强制CLR立即终止进程,因此确保您了解可能抛出的异常并对其进行处理。 - Mahol25
1个回答

0

我创建了一个抽象的com包装器类,从中派生出所有我的com包装器类。它运行非常良好。我的原始代码是VB,因为我需要晚期绑定(这是在C#引入dynamic类型之前)。我的应用程序的其余部分是用C#编写的。

public abstract class ComWrapper : IDisposable
{
    protected internal object _comObject;
    protected ComWrapper(object comObject)
    {
        _comObject = comObject;
    }

    #region " IDisposable Support "

    private bool _disposed = false;

    protected virtual void FreeManagedObjects()
    {
    }

    protected virtual void FreeUnmanagedObjects()
    {
        ReleaseComObject(_comObject);
    }

    private void Dispose(bool disposing)
    {
        if (!_disposed) {
            if (disposing) {
                FreeManagedObjects();
            }
            FreeUnmanagedObjects();
            _disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected override void Finalize()
    {
        Dispose(false);
        base.Finalize();
    }

    #endregion
}

并且

public static class Helpers
{
    public static void ReleaseComObject(ref object o)
    {
        if ((o != null)) {
            try {
                Marshal.ReleaseComObject(o);
            } catch {
            } finally {
                o = null;
            }
        }
    }

    public static string ToDotNetString(object comString)
    {
        if (comString == null) {
            return string.Empty;
        }
        string s = comString.ToString();
        ReleaseComObject(ref comString);
        return s;
    }
}

这并没有真正回答我的问题(或者能够编译)。 - Justin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接