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