IntPtr, SafeHandle и HandleRef - Объяснено - PullRequest
36 голосов
/ 09 февраля 2009

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

Ответы [ 3 ]

49 голосов
/ 09 февраля 2009

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

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

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

17 голосов
/ 18 февраля 2010
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, ...);

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

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

1 голос
/ 07 января 2016

Похоже, что SafeHandle включает в себя поведение KeepAlive HandleRef: Проект 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's Dispose () вручную, чтобы предотвратить утечку ресурсов дело, я прав? Может кто-нибудь объяснить исходный код, что такое

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...