C++/CLI:防止非托管资源的托管包装上的垃圾回收

Lau*_*ent 11 c# garbage-collection c++-cli finalizer

我有一个NativeDog需要在C#中使用的C++非托管类,所以我创建了一个包装类ManagedDog.

// unmanaged C++ class
class NativeDog
{
    NativeDog(...); // constructor
    ~NativeDog(); // destructor
    ...
}

// C++/CLI wrapper class
ref class ManagedDog
{
    NativeDog* innerObject; // unmanaged, but private, won't be seen from C#
    ManagedDog(...)
    {
        innerObject = new NativeDog(...);
        ...
    }

    ~ManagedDog() // destructor (like Dispose() in C#)
    {
        // free unmanaged resources
        if (innerObject)
            delete innerObject;
    }

    !ManagedDog() // finalizer (like Finalize() in C#, in case
    {             // the user forgets to dispose)
        ~ManagedDog(); // call destructor
    }
}
Run Code Online (Sandbox Code Playgroud)

一切都很好,我使用这样的类:

// in C++/CLI
// this function is called from C++ code
void MyLibrary::FeedDogNative(NativeDog* nativedog)
{
    ... // (***)
}
// this function is called from C#, passes on the dog to the native function
void MyLibrary::FeedDogManaged(ManagedDog^ dog)
{
    NativeDog* rawdog = dog->innerObject;
    MyLibrary::FeedDogNative(rawdog);
}

// C# client code
void MyFunc()
{
    ManagedDog dog = new ManagedDog(...);
    MyLibrary.FeedDogManaged(dog);
}
Run Code Online (Sandbox Code Playgroud)

看错了什么?我一开始都没有,直到很多奇怪的事情不时发生.基本上如果在调用MyFunc()程序后,当GC在本机函数中的某个位置FeedDogNative((***)上面标记)暂停时,它会认为托管包装器可以被收集,因为它将不再被使用,也不会在C#MyFunc中使用(它是本地的)变量,并且不会在FeedDogManaged通话后使用),也不会在FeedDogManaged.所以这实际上偶尔会发生.GC调用Finalizer,它delete是本地狗对象,即使FeedDogNative还没有完成使用它!所以我的非托管代码现在使用已删除的指针.

我怎么能阻止这个?我可以想到一些方法(例如假装dog在最后使用的假电话FeedDogManaged),但推荐的方式是什么?

max*_*max 7

您需要GC::KeepAlive()FeedDogManaged函数中调用.似乎它是一个确切的用例.