GCHandle para obtener la dirección (puntero) del objeto .net

Logré obtener la dirección de un objeto .net por

GCHandle objHandle = GCHandle.Alloc(obj,GCHandleType.WeakTrackResurrection); int address = GCHandle.ToIntPtr(objHandle).ToInt32(); 

y puedo recordar el objeto por

 Object obj = GCHandle.FromIntPtr(IntPtr(address)).Target; 

Bueno, el propósito es almacenar la dirección en una clase nativa y tener una información de qué objeto nativo se vuelve a conectar a qué objeto .net.
AFAIK la dirección no cambia debido a la asignación, ¿es cierto o alguien tiene una mejor idea para cumplir mi propósito?

Gracias

Como lo han señalado Tim y thecoop, GCHandle.Alloc puede evitar la recolección de basura, pero la dirección real del objeto puede cambiar a medida que GC puede mover el objeto a menos que se pinche el objeto. Además, su código está utilizando GCHandleType.WeakTrackResurrection y eso no evitaría la recolección de basura. GCHandle.ToIntPtr le dará una dirección de manejo que se puede redondear a través de una llamada no administrada. La dirección real del objeto será dada por el método AddrOfPinnedObject .

Dicho todo esto, IMO, su código puede servir para asociar un objeto .NET con un objeto no administrado. Esto se debe a que GCHandle.To/FromIntPtr le devolverá la corrección de GCHandle y podrá alcanzar su objeto .NET a través de él (siempre que no se haya recogido la basura). En mi opinión, debería ser irrelevante si la dirección real del objeto ha cambiado o no.

Querrá fijar el GCHandle para evitar que el objeto se mueva, ya que el GC mueve los objetos, por lo que un puntero no clavado podría quedar inválido. Al sujetar el objeto se detiene el movimiento:

 GCHandle handle = GCHandle.Alloc(obj, GCHandleType.Pinned); IntPtr ptr = handle.AddrOfPinnedObject(); 

También tendrás que liberar el mango cuando hayas terminado:

 handle.Free(); 

Lo que está recibiendo no es realmente una dirección.

Como notará, parece actuar como una dirección la mayor parte del tiempo, y puede recuperar el objeto utilizando GCHandle.FromIntPtr. Sin embargo, el problema interesante es que está utilizando GCHandleType.WeakTrackResurrection .

Si su objeto con una referencia débil se recolecta (probablemente se puede, ya que solo tiene una referencia débil por parte del GCHandle), todavía tiene el IntPtr, y puede pasarlo a GCHandle.FromIntPtr () . Si lo hace, entonces vuelve a ser nulo, asumiendo que el IntPtr no ha sido reciclado.

(Si el CLR ha reciclado el IntPtr por alguna razón, entonces está en problemas. No estoy seguro de que esto pueda suceder).

Es mejor utilizar GCHandleType.Normal o GCHandleType.Pinned (si necesita tomar la dirección del objeto en un código no administrado), si desea una referencia segura al objeto.

(Para usar GCHandleType.Pinned, su objeto debe ser primitivo, o debe tener el atributo [StructLayout], o ser una matriz de dichos objetos.)

AFAIK la dirección no cambia debido a la asignación, ¿es verdadera?

La dirección de un objeto gestionado cambia. El recolector de basura es libre de mover objetos en la memoria. Cuando se ejecuta el recolector de basura, recostack objetos no utilizados y luego reorganiza los objetos restantes para minimizar el tamaño general del montón administrado.

¿Alguien tiene una mejor idea para cumplir mi propósito?

No estoy seguro de que encuentre una buena forma de mantener un puntero para un objeto administrado durante largos períodos de tiempo. Es posible fijar objetos en la memoria y obtener su dirección de esa manera, pero en C # es posible fijar objetos solo dentro de un solo método.

Te ayudaría si explicaras con más detalle qué vas a hacer con el puntero una vez que lo tengas.