我需要固定匿名代表吗?
我从C#应用程序调用CopyFileEx,并将匿名委托传递给LPPROGRESS_ROUTINE参数,以便获取有关文件复制进度的通知。
我的问题是,匿名代表是否需要固定以及为什么(或为什么不)。
此外,如果:
- CopyFileEx没有阻止。
- 如果我传入一个非匿名的代表。
谢谢!
代表不需要固定 。 如果无法通过垃圾收集器移动托管对象,则将其固定 。 如果编组信息是正确的,那么编组层将确保传递指向不动的东西的指针。
但是,上面的注释中您建议局部变量可能使委托保持活动,这表明对变量生命周期的误解。 我推荐你的规范,其中说明:
局部变量的实际生命周期取决于实现。 例如,编译器可能静态地确定块中的局部变量仅用于该块的一小部分。 使用此分析,编译器可以生成导致变量存储的生命周期比其包含块短的代码。 由本地引用变量引用的存储器被回收,而与该本地引用变量的寿命无关
换句话说,如果你说:
void M() { Foo foo = GetAFoo(); UnmanagedLibrary.DoSomethingToFoo(foo); }
然后允许抖动说“你知道,我发现在调用非托管调用之后,没有托管代码再次使用foo;因此我可以积极地从另一个线程中回收该对象的存储”。 这意味着非托管调用可以在突然在另一个线程上释放时对该对象起作用。
如果Foo有一个析构函数,这尤其令人讨厌。 当对象由非托管库使用时,终结代码可能在另一个线程上运行,而天堂只知道将导致什么样的灾难。
在这种情况下,您需要使用KeepAlive来保持托管对象的活动。 不要依赖局部变量; 局部变量具体记录为不保证保持活力。
有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx 。
您不需要固定它,但只要副本正在进行中,您确实需要保持对它的引用。
由非托管代码调用的thunk是固定的,但您必须确保委托不是垃圾收集 – 因此是引用。
从下面的msdn看起来像pinning和GC.KeepAlive在这种情况下是不需要的,因为CopyFileEx是同步的。 具体来说它说:
“通常,您不必担心委托的生命周期。每当您将委托传递给非托管代码时,CLR将确保委托在调用期间处于活动状态。但是,如果本机代码保留了代理的副本超出调用范围的指针,并打算稍后通过该指针回调,您可能需要使用GCHandle显式阻止垃圾收集器收集委托。“
由于CopyFileEx不会在调用范围之外保留指向函数的指针,因此我们不需要调用KeepAlive。