Как нестатические обратные вызовы работают из собственного кода?

Немного странно задавать этот вопрос, потому что у меня есть код, который, кажется, не должен работать, но он работает, и хотя я не жалуюсь, я хотел бы подтвердить, почему? РЖУ НЕ МОГУ

Просто у меня есть собственная DLL C++ (без CLR/управляемой поддержки вообще), которая принимает обратный вызов из кода C#. Нативная сторона хранит функцию обратного вызова stdcall, которая предоставляется стороной C#. Я всегда думал, что МЕТОД обратного вызова (в С#) должен быть статическим, но нестатическое и лямбда-выражение ОБА работают ПРОСТО ХОРОШО!? Как указатель «this» маршалируется из собственного кода? Я всегда думал, что нативный код хранит только указатели на функции, не относящиеся к экземпляру?

Теперь я нашел статью, в которой какой-то парень создал код IL для «моста» между собственными и нестатическими управляемыми обратными вызовами. Я также заметил этот устаревший метод: «Marshal.GetUnmanagedThunkForManagedMethodPtr()». Этот метод больше не поддерживается, что, как я предполагаю, означает, что он встроен?

Резюме вопроса:

  1. Является ли преобразование теперь встроенным в .NET путем создания кода IL? Если да, то в какой версии .NET это стало изначально поддерживаться?

  2. Поддерживается ли неявное «thunking» в Mono?

  3. Когда IL генерируется для управляемых обратных вызовов, что происходит, когда экземпляр, на который ссылается преобразователь, удаляется? Удален ли IL, или это может привести, так сказать, к "утечке" памяти?

Спасибо.


person James Wilkins    schedule 27.03.2013    source источник


Ответы (2)


Является ли преобразование теперь встроенным в .NET путем создания кода IL? Если да, то в какой версии .NET это стало изначально поддерживаться?

IL не участвует в преобразовании, это происходит путем создания собственного кода — батута, который переставляет аргументы в соответствии с соглашением о вызовах .NET, включая указатель this, который сохраняется в случае закрытых делегатов, а затем выполняет хвостовой вызов . NET сам метод.

Поддерживается ли неявное «thunking» в Mono?

Это называется "обратный вызов p/invoke", что должно упростить поиск в документации Mono.

Когда IL генерируется для управляемых обратных вызовов, что происходит, когда экземпляр, на который ссылается преобразователь, удаляется?

Когда делегат очищается от мусора, память, используемая батутом, также освобождается. Поэтому вам нужно поддерживать делегат, пока в нативном коде есть указатель на трамплин.

person Ben Voigt    schedule 27.03.2013

Маршаллер взаимодействия просто маршалирует делегата. Делегат может быть либо делегатом класса (без this), либо делегатом экземпляра (имеет this). С точки зрения C# это просто вызов делегата. т. е. эффективно используется та же семантика, что и для управления this с делегатом экземпляра (например, разделение экземпляра класса).

Очевидно, что под прикрытием происходит больше других вещей (таких как закрепление и т. д.), но они, как правило, не связаны с тем, о чем вы спрашивали.

person Peter Ritchie    schedule 27.03.2013
comment
Я понял это, но приятно явно указать это для других, так как мне было трудно найти достоверную информацию об этом. ;) - person James Wilkins; 29.03.2013