Laden...

Technische Identität (Adresse) ermitten?

Erstellt von herbivore vor 18 Jahren Letzter Beitrag vor 18 Jahren 3.134 Views
herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 18 Jahren
Technische Identität (Adresse) ermitten?

Hallo Community,

wie kann ich die (Speicher-)Adresse eines Objekts (als Zahl) bekommen?

Ich möchte mir zu einem Objekt in einem Dictionary (Hashtable) den Zustand diese Objekts merken. Leider kann ich nicht einfach

dict [obj] = ...

benutzen, weil dann für zwei Objekte mit demselben Zustand nur einen Eintrag bekommt. Außerdem dürfen Objekte, die man als Key eines Dictionary benutzt, ihren Zustand nicht ändern, weil sie dann einen anderen Hashcode liefern. Es geht ja aber gerade um Objekte, deren Zustand sich ändern kann. Ich bräuchte also eine eindeutige Id eines Objekte, z.B. eben seine Adresse.

Wenn ich &obj benutze, muss ich zum einen unsafe benutzen, was ich sehr gerne vermeiden würde, zum anderen meckert er:

error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('object') => Selbst bei Verwendung mit dem unsafe-Schlüsselwort ist es nicht zulässig, die Adresse eines verwalteten Objekts zu übernehmen.

Scheinbar kommt mal also mit &obj nicht weiter. Ich ja aber gar nichts böses mit der Adresse machen, sondern sie einfach nur als Zahl wissen.

Würde mich über Vorschläge freuen. Vielen Dank!

herbivore

1.373 Beiträge seit 2004
vor 18 Jahren

Die Addresse des Objekts nützt dir gar nichts, selbst wenn du sie bekommen könntest, da sie sich ja nach einer Garbage Collection einfach so ändern kann.

Wenn die Klasse Equals nicht überschreibt, wird die Object-Version genommen. Diese überprüft auf Referenz-Gleichheit. Für zwei unterschiedliche Objekte gäbe es daher zwei Einträge in die Hashtable.

Wenn Equals schon überschrieben wurde, würde ich einfach einen eigenen IEqualityComparer anbieten, dessen Equals-Methode Object.ReferenceEquals(x, y) zurückgibt. GetHashCode könnte einfach GetHashCode des übergebenen Objekts zurückgeben.

MfG VizOne

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 18 Jahren

Hallo VizOne,

danke schon mal für die Antwort!

Ich vergaß zu sagen, dass sichergestellt wird, dass die Objekte, deren Zustand im Dictionary gespeichert wird, nicht in die Hände des GCs fallen.

Da es sich um beliebige Objekte handeln können soll, weiß ich nicht, ob und wie Equals überschrieben ist und ich weiß auch nicht ob und wie GetHashCode überschrieben ist.

Das Equals-Problem lässt sich lösen, wenn man - wie von dir vorgeschlagen - den IEqualityComparer mit ReferenceEquals implementiert.

Für das GetHashCode-Problem sehe ich keine Lösung, denn:

Die Standardimplementierung von GetHashCode garantiert weder Eindeutigkeit noch Konsistenz. Sie darf daher nicht als einziger Objektbezeichner für das Hashing verwendet werden. Abgeleitete Klassen müssen GetHashCode mit einer Implementierung überschreiben, die einen eindeutigen Hashcode zurückgibt. Die besten Ergebnisse werden erzielt, wenn der Hashcode auf dem Wert eines Instanzfeldes oder einer Instanzeigenschaft und nicht auf dem Wert eines statischen Feldes oder einer statischen Eigenschaft beruht.

Vielleicht fällt dir ja dafür auch noch was ein.

herbivore

1.373 Beiträge seit 2004
vor 18 Jahren

Die Hashtable verwendet den Hash ja nur als ersten Hinweis darauf, wo das Objekt liegen könnte. Ab dann wird Equals verwendet um das Objekt zu finden. Das heißt, dass die verwendete GetHashCode() Implementierung für den Erfolg vollkommen egal ist, solange sie sich an die Vorgaben hält (v.A. dass sich der Hashcode nicht ändert). Die Hashfunktion hat lediglich Einfluss darauf, wie gut (=mit wenig Kollisionen) die Objekte in der Hashtable verteilt sind. Das sollte dich aber nicht weiter kümmern. Probier es aus mit dem IEqualityComparer, es wird schon funktionieren.

MfG VizOne

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 18 Jahren

Hallo VizOne,

soweit ist mir das klar. Allerdings eignet sich die Standard-Implementierung von GetHashCode, die ja immer zum Zuge kommt, wenn die Klasse nicht selbst was implementiert, eben nicht für diese erste Positionsangabe, zumindest, wenn man der Doku glauben schenken will:

Die Standardimplementierung von GetHashCode garantiert weder Eindeutigkeit noch Konsistenz.

Und wenn die erste Positionsangabe schon falsch ist, nützt es auch nichts, wenn der anschließende Vergleich korrekt läuft.

Bei Hashtable gibt es einen - mittlerweile als obsolet gekennzeichneten - Konstuktor mit IHashcodeProvider. Das ist im Prinzip, was ich will. Dass ich den HashCode der Objekte zur Verfügung stellen kann (natürlich müsste ich dann auch einen zu dem Hashcode passenden Gleichheitsvergleich zur Verfügung stellen). Und als Hashcode möchte ich eben die (technische) Identität (=Adresse) der Objekte verwenden.

So wie man ja mit ReferenceEquals letztendlich auch die Adressen vergleicht, möchte ich einen auf den Adressen basierenden Hashcode benutzen.

Auch wenn ich es zum Teil sehr technisch beschreibe, ist das m.E. ein sehr legitimer Wunsch. So wie ich die Identität zweier Objekte vergleichen kann, möchte ich die Identität eines Objekt als Key eines Dictionary benutzen.

Würde mich freuen, wenn es doch noch eine Lösung gäbe.

herbivore

1.373 Beiträge seit 2004
vor 18 Jahren

IEqualityComparer hat auch eine Methode zum Generieren von Hashcodes, so wie IHashProvider.

Hm, bisher konnte ich aber z.B. auch immer Objekte mit der Standardimplementierung von GetHashCode in hashtables etc. verwenden, da gab es nie Probleme. Hab da aber auch noch nicht so detailliert drüber nachgedacht. Wahrscheinlich wird nicht garantiert, dass gleiche Objekte gleiche Hashcodes kriegen. Wäre aber in deinem Fall ja auch nicht tragisch, bzw. nicht mal beabsichtigt.

Wenn du die Adresse eines Objektes haben willst, geht das über ein System.Runtime.InteropServices.GCHandle. Du musst für jedes Objekt ein handle mit GCHandleType.Pinned anlegen und kriegst dann mittels AddrOfPinnedObject die Adresse. Denk daran, dass die Objekte aber nicht vom GC verschoben werden können, solange das Handle aktiv ist, also möglichst schnell das Handle wieder mit Free() aufheben.

MfG VizOne

herbivore Themenstarter:in
49.485 Beiträge seit 2005
vor 18 Jahren

Hallo VizOne,

das mit dem System.Runtime.InteropServices.GCHandle sieht doch schon mal sehr vielversprechend aus.

Vielen Dank!

herbivore