2009-02-08 10 views
33

Sin señalarme a MSDN, podría alguien dar una explicación clara y concisa del propósito de cada uno de estos y cuándo usarlos. (IntPtr, SafeHandle y HandleRef)IntPtr, SafeHandle y HandleRef - Explicación

+1

¿Qué pasa con MSDN? –

+8

Nada. Solo estoy buscando un breve resumen de cada uno para asegurarme de que los estoy usando correctamente. Si leo las descripciones de MSDN y de otras personas, tengo una mejor idea de si lo que estoy haciendo es correcto. – user62572

Respuesta

46

IntPtr es simplemente una estructura simple basada en enteros que puede contener un puntero (es decir, tamaño de 32 bits en sistemas de 32 bits, tamaño de 64 bits en sistemas de 64 bits).

SafeHandle es una clase que está destinada a contener identificadores de objetos Win32; tiene un finalizador que asegura que el identificador se cierre cuando el objeto recibe GC. SafeHandle es una clase abstracta porque los diferentes identificadores de Win32 tienen diferentes formas en que deben cerrarse. Antes de la introducción de SafeHandle, IntPtr se usaba para mantener los identificadores de Win32, pero asegurarse de que se cerraran correctamente y se evitara que pasaran por GC era responsabilidad del programador.

HandleRef es una forma de asegurarse de que un identificador no administrado no recibe GC cuando está en medio de una llamada P/Invoke. Sin algo como HandleRef, si su código administrado no hace nada con el controlador después de la llamada P/Invoke, si el GC se ejecutó durante la llamada P/Invoke no se daría cuenta de que el identificador aún estaba en uso y podría GC . Me imagino (pero no estoy seguro y no lo he buscado) que SafeHandle podría usar HandleRef como parte de su gestión del identificador encapsulado.

+13

Corrección secundaria. Use HandleRef cuando no desee un objeto * managed * GC'ed durante PInvoke. por ejemplo clase HWnd {public IntPtr Handle; } HWnd a = new HWnd(); B.SendMessage (a.Handle, ...); <- a podría recibir GC en PInvoke B.SendMessage (new HandleRef (a, a.Handle)) <- ahora no se puede aplicar GC en PInvoke –

+3

Otra adición: 'SafeHandle' incluye recuento de referencias para prevenir manejar ataques de reciclaje. –

+0

¿Alguien puede confirmar que safehandle usa handleref?¿O al menos tiene un mecanismo similar? – Assimilater

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

Suponiendo que esta es la única referencia a "a" en el programa, esto es equivalente a:

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

El problema es que cuando "a" está dispuesto, se va a cerrar el mango. Si esto ocurre antes o durante la llamada a SendMessage, el identificador no será válido.

HandleRef evita que se recolecte "a" basura antes de que el programa se termine con h.

1

Parece que SafeHandle no incorporar el comportamiento KeepAlive de HandleRef: Project 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) 
<...> 
*/ 

Pero no estoy seguro, parece que el comportamiento de mantenimiento de conexión solamente se puede lograr proporcionando valor falso al constructor, que simplemente marca el objeto como no finalizable, por lo que debe llamar a SafeHandle's Dispose() manualmente para evitar la fuga de recursos en ese caso, ¿estoy en lo cierto? Puede alguien explicar el código fuente, lo que es el

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

?