防止委托被垃圾收集

4 c# c++-cli

我目前正在尝试将C#委托编组为C++函数指针,我查看了Microsoft示例:

// MarshalDelegate1.cpp
// compile with: /clr
#include <iostream>

using namespace System;
using namespace System::Runtime::InteropServices;

#pragma unmanaged

// Declare an unmanaged function type that takes two int arguments
// Note the use of __stdcall for compatibility with managed code
typedef int (__stdcall *ANSWERCB)(int, int);

int TakesCallback(ANSWERCB fp, int n, int m) {
   printf_s("[unmanaged] got callback address, calling it...\n");
   return fp(n, m);
}

#pragma managed

public delegate int GetTheAnswerDelegate(int, int);

int GetNumber(int n, int m) {
   Console::WriteLine("[managed] callback!");
   return n + m;
}

int main() {
   GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber);
   GCHandle gch = GCHandle::Alloc(fp);
   IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
   ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer());
   Console::WriteLine("[managed] sending delegate as callback...");

// force garbage collection cycle to prove
// that the delegate doesn't get disposed
   GC::Collect();

   int answer = TakesCallback(cb, 243, 257);

// release reference to delegate
   gch.Free();
}
Run Code Online (Sandbox Code Playgroud)

GCHandle :: Alloc()的调用应该阻止垃圾收集器收集委托.但我的理解是,变量GetTheAnswerDelegate ^ fp已经使委托保持活动状态,因为它是一个根对象,即使我删除对GCHandle的调用,该示例仍然有效.只有当我像这样内联委托实例化时:

IntPtr ip = Marshal::GetFunctionPointerForDelegate(gcnew GetTheAnswerDelegate(GetNumber));
Run Code Online (Sandbox Code Playgroud)

然后我看到了崩溃.

微软的例子是错的还是我错过了什么?

Han*_*ant 7

您缺少使用调试器对局部变量的生命周期的影响.附加调试器后,抖动会将使用的变量标记为方法结束.重要的是使调试可靠.但是这也会阻止GC.Collect()调用收集委托对象.

在没有调试器的情况下运行程序的Release版本时,此代码将崩溃.

在对垃圾收集器调试版本行为的影响进行了深入的答案是提供这个职位