The delegate does not need to be pinned. A managed object is pinned if it cannot be moved by the garbage collector. If the marshalling information is correct then the marshalling layer will ensure that a pointer to something immobile is passed.
However, the comment above where you suggest that a local variable might keep the delegate alive indicates a misunderstanding of variable lifetime. I refer you to the spec, which states:
The actual lifetime of a local variable is implementation-dependent. For example, a compiler might statically determine that a local variable in a block is only used for a small portion of that block. Using this analysis, the compiler could generate code that results in the variable’s storage having a shorter lifetime than its containing block.
The storage referred to by a local reference variable is reclaimed independently of the lifetime of that local reference variable
In other words, if you say:
void M()
{
Foo foo = GetAFoo();
UnmanagedLibrary.DoSomethingToFoo(foo);
}
then the jitter is allowed to say "you know, I see that no managed code ever uses foo again the moment after the unmanaged call is invoked; I can therefore aggressively reclaim the storage of that object from another thread at that time". Which means that the unmanaged call can be working on the object when suddenly it is deallocated on another thread.
This is particularly nasty if Foo has a destructor. The finalization code will possibly run on another thread while the object is in use by the unmanaged library, and heaven only knows what sort of disaster that will cause.
In this circumstance you are required to use a KeepAlive to keep the managed object alive. Do not rely on a local variable; local variables are specifically documented as not guaranteed to keep things alive.
See http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx for more details.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…