Подтвердить что ты не робот

IntPtr, SafeHandle и HandleRef - Разъяснения

Не указывая мне на MSDN, кто-то может дать краткое, ясное объяснение цели каждого из них и когда их использовать. (IntPtr, SafeHandle и HandleRef)

4b9b3361

Ответ 1

IntPtr - это простая структура на основе целых чисел, которая может содержать указатель (т.е. 32-разрядный размер в 32-битных системах, размер 64-разрядных в 64-разрядных системах).

SafeHandle - это класс, предназначенный для хранения дескрипторов объектов Win32 - он имеет финализатор, который гарантирует, что дескриптор закрыт, когда объект GC'ed. SafeHandle - абстрактный класс, потому что разные дескрипторы Win32 имеют разные способы их закрытия. До введения SafeHandle, IntPtr использовался для хранения дескрипторов Win32, но ответственность за то, чтобы они были должным образом закрыты и не были защищены от GC'ed, была ответственностью программиста.

HandleRef - это способ убедиться, что неуправляемый дескриптор не GC, если вы находитесь в середине вызова P/Invoke. Если что-то вроде HandleRef, если ваш управляемый код ничего не делает с дескриптором после вызова P/Invoke, если GC был запущен во время вызова P/Invoke, он не понимает, что дескриптор все еще используется и может GC это. Я предполагаю (но я не уверен и не смотрел), что SafeHandle может использовать HandleRef как часть управления инкапсулированным дескриптором.

Ответ 2

HWnd a = new HWnd();
B.SendMessage(a.Handle, ...);

Предполагая, что это единственная ссылка на "a" в программе, это эквивалентно:

HWnd a = new HWnd();
IntPtr h = a.Handle;
// a is no longer needed and thus can be GC'ed
B.SendMessage(h, ...);

Проблема заключается в том, что когда "a" располагается, он закрывает дескриптор. Если это произойдет до или во время вызова SendMessage, дескриптор будет недействительным.

HandleRef предотвращает "а" от сбора мусора до того, как программа будет выполнена с помощью h.

Ответ 3

Похоже, что SafeHandle использует поведение HandleRef KeepAlive: Проект Roslyn SafeHandle.cs http://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/safehandle.cs,743afbddafaea263

/*
  Problems addressed by the SafeHandle class:
  1) Critical finalization - ensure we never leak OS resources in SQL.  Done
     without running truly arbitrary & unbounded amounts of managed code.
  2) Reduced graph promotion - during finalization, keep object graph small
  3) GC.KeepAlive behavior - P/Invoke vs. finalizer thread ---- (HandleRef)
<...>
*/

Но я не уверен, похоже, что поведение keepalive может быть достигнуто только путем предоставления ложного значения конструктору, который просто отмечает объект как не подлежащий окончательной обработке, поэтому вам нужно вызвать SafeHandle Dispose() вручную, чтобы предотвратить утечку ресурсов в этом Случай, я прав? Может кто-нибудь объяснить исходный код, что такое

private extern void InternalDispose();
private extern void InternalFinalize();

?