Делегат не должен быть закреплен .Управляемый объект закрепляется , если он не может быть перемещен сборщиком мусора.Если информация о маршаллинге верна, то уровень, обеспечивающий маршалинг, обеспечит передачу указателя на что-то неподвижное.
Тем не менее, приведенный выше комментарий, в котором вы предполагаете, что локальная переменная может сохранить делегата живым указывает на недопонимание переменной жизни.Я отсылаю вас к спецификации, которая гласит:
Фактическое время жизни локальной переменной зависит от реализации.Например, компилятор может статически определить, что локальная переменная в блоке используется только для небольшой части этого блока.Используя этот анализ, компилятор может сгенерировать код, в результате которого срок хранения переменной будет меньше, чем у содержащего ее блока.Память, на которую ссылается локальная ссылочная переменная, восстанавливается независимо от времени жизни этой локальной ссылочной переменной
Другими словами, если вы говорите:
void M()
{
Foo foo = GetAFoo();
UnmanagedLibrary.DoSomethingToFoo(foo);
}
, тогда дрожаниеразрешено говорить «вы знаете, я вижу, что ни один управляемый код никогда не использует foo снова в тот момент, после того, как неуправляемый вызов вызван; поэтому я могу настойчиво вернуть хранилище этого объекта из другого потока в то время».Это означает, что неуправляемый вызов может работать с объектом, когда он внезапно освобождается в другом потоке.
Это особенно неприятно, если у Foo есть деструктор.Код завершения, возможно, будет выполняться в другом потоке, пока объект используется неуправляемой библиотекой, и небеса знают только, какую катастрофу это вызовет.
В этом случае вам необходимо использоватьKeepAlive, чтобы поддерживать управляемый объект. Не полагайтесь на локальную переменную;Локальные переменные специально задокументированы как , а не , гарантированно поддерживающие жизнь.
Подробнее см. http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx.