GCHandle для получения адреса (указателя) объекта .net - PullRequest
5 голосов
/ 04 ноября 2010

Мне удалось получить адрес объекта .net по

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

, и я могу вызвать объект по

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

Ну, цель состоит в том, чтобы сохранить адрес внативный класс и имеет информацию о том, какой нативный объект передан какому объекту .net.
AFAIK адрес не изменяется из-за выделения, это правда, или у кого-то есть идея лучше, чтобы служить моей цели?

Спасибо

Ответы [ 4 ]

7 голосов
/ 04 ноября 2010

Вы захотите закрепить GCHandle, чтобы остановить перемещение объекта, поскольку GC перемещает объекты вокруг, так что закрепленный указатель может стать недействительным. Закрепление объекта останавливает его движение:

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

Вам также придется освободить ручку, когда вы закончите:

handle.Free();
5 голосов
/ 04 ноября 2010

Как указал Тим и thecoop, GCHandle.Alloc может запретить сборку мусора, но фактический адрес объекта может измениться, так как GC может перемещать объект, если вы не закрепите объект.Кроме того, ваш код использует GCHandleType.WeakTrackResurrection, и это не может предотвратить сборку мусора.GCHandle.ToIntPtr выдаст адрес дескриптора, который можно переключить в обход по неуправляемому вызову.Фактический адрес объекта будет предоставлен методом AddrOfPinnedObject.

Сказав все это, IMO, ваш код может служить для связи объекта .NET с неуправляемым объектом.Это потому, что GCHandle.To/FromIntPtr вернет вам правильный GCHandle, и вы сможете через него получить доступ к объекту .NET (при условии, что он не собран мусором).ИМО, должно быть несущественно, изменился фактический адрес объекта или нет.

2 голосов
/ 19 января 2011

То, что вы получаете, на самом деле не является адресом.

Как вы заметили, в большинстве случаев он действует как адрес, и вы можете вызвать объект, используя GCHandle.FromIntPtr. Однако интересная проблема заключается в том, что вы используете GCHandleType.WeakTrackResurrection .

Если ваш объект со слабой ссылкой получен (вероятно, может, так как GCHandle ссылается на него слабо), у вас все еще есть IntPtr, и вы можете передать его в GCHandle.FromIntPtr () . Если вы сделаете это, вы получите нулевое значение, при условии, что IntPtr не был переработан.

(Если по какой-либо причине CLR переработал IntPtr, у вас возникли проблемы. Я не уверен, может ли это произойти.)

Вам лучше использовать либо GCHandleType.Normal , либо GCHandleType.Pinned (если вам нужно взять адрес объекта в неуправляемом коде), если вы хотите сильный ссылка на объект.

(Чтобы использовать GCHandleType.Pinned, ваш объект должен быть, например, примитивным, иметь атрибут [StructLayout] или быть массивом таких объектов.)

1 голос
/ 04 ноября 2010

AFAIK адрес не изменяется из-за выделения, верно ли это

Адрес управляемого объекта меняет . Сборщик мусора может свободно перемещать объекты в памяти. При запуске сборщика мусора он собирает неиспользуемые объекты, а затем переставляет оставшиеся объекты, чтобы минимизировать общий размер управляемой кучи.

Кто-нибудь имеет лучшую идею, чтобы служить моей цели?

Я не уверен, что вы найдете хороший способ удерживать указатель на управляемом объекте в течение длительных периодов времени. Можно закрепить объекты в памяти и получить их адрес таким образом, но в C # объекты можно закрепить только в одном методе.

Было бы полезно, если бы вы более подробно объяснили, что вы будете делать с указателем, как только он у вас будет.

...