Ersetzen-Objekt-Instanz durch eine andere in C#
In dieser Frage möchte ich herausfinden, ob und wie das möglich ist. Diese Technik scheint sehr schlechte Praxis, aber es scheint, dass die API (UnityEditor), die ich verwende, ist etwas wie das zu tun und ich bin einfach nur neugierig.
Wenn es mehrere Referenzen auf das gleiche Objekt, ist es möglich zu instanziieren eines neuen Objektes in der gleichen Speicher-slot, so dass alle bisherigen Verweise zeigen auf das neue Objekt?
Ich herausgefunden, dass die einzige praktikable Möglichkeit, dies zu tun ist durch die Verwendung von nicht verwaltetem C++. Im wesentlichen ist Folgendes passiert:
//Original prefab
GameObject prefab = x;
prefab.tag = "Untagged";
//A copy of the original prefab
GameObject prefabCopy = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
prefabCopy.tag = "EditorOnly"; //Change from initial value "Untagged"
Debug.Log(prefab.tag); //"Untagged" - expected
Debug.Log(prefabCopy.tag); //"EditorOnly" - expected
//Replace contents of prefab file with `prefabCopy`
PrefabUtility.ReplacePrefab(prefabCopy, prefab);
//Destroy the copy
DestroyImmediate(prefabCopy);
Debug.Log(prefab.tag); //"EditorOnly" - whoa?
Einige, wie prefab
zeigt jetzt auf ein anderes Objekt?
Hinweis: Bedenken Sie, dass die Einheit gebaut ist, auf der Oberseite des Mono-Geschmack .NET
PrefabUtility.ReplacePrefab(prefabCopy, prefab);
?PrefabUtility.ReplacePrefab
ruft eine interne Methode (nach der assembly-browser).InformationsquelleAutor Lea Hayes | 2012-07-07
Du musst angemeldet sein, um einen Kommentar abzugeben.
Da ein Objekt-Zustand ist definiert durch die Werte, die Sie kopieren können Speicher, mit Feld-Werte von einem Objekt zu einem anderen, wirksam "einbauen":
Beachten Sie, dass dieser code erfordert
[StructLayout(LayoutKind.Sequential)]
(oderLayoutKind.Explicit
) Attribut für eine Klasse definiert.UnityEngine.Object
hat[StructLayout (LayoutKind.Sequential)]
Einheit überlast alle Geschlechter Betreiber, die ungewöhnliche Dinge mögen, vergleichen Sie positiv mit
null
nach zerstört wird. Gibt es eine Möglichkeit mitMarshal
anzeigen, um eine string-Darstellung eines Zeigers? Ich möchte vergleichen die Referenz derprefab
mit der return-Wert vonPrefabUtility.ReplacePrefab
ohne Einheit vornehmen zu können, jede Art von schwarzer Magie.Können Sie Holen Sie sich die Adresse von Objekten mit
var gch = GCHandle.Alloc(obj, GCHandleType.Pinned); var address = gch.AddrOfPinnedObject(); gch.Free()
, aber es wird nicht funktionieren für die meisten Objekttypen. Ich denke, dass ist so nah an der Objekt-Adresse, die Sie bekommen können. Wie auch immer, ich glaube nicht, dass es eine chance, dass sich etwas verändert Referenzen in Ihrem code anstelle von Objekt-Instanzen (außer für den garbage collector natürlich).Ich hatte gehofft, zu folgern, ob der aktualisierte prefab Referenz war das gleiche wie das original, da dies implizieren würde, dass das Objekt wiederverwendet werden. Leider funktionierte dies nicht, die für dieses Objekt Typ
ArgumentException: Object contains non-primitive or non-blittable data.
Prost 🙂Ich habe akzeptiert diese Antwort, weil ich denke, dass es die meisten wahrscheinlich-insbesondere angesichts der Tatsache, dass die
StructLayout
- Attribut vorhanden ist.InformationsquelleAutor max
Könnten Sie tun, wenn Sie binden Sie Ihr Objekt in ein anderes, das verwendet wird, um auf das Objekt zuzugreifen.
Nun erstellen Sie mehrere Referenzen auf ein Objekt vom Typ
MyObjectReference
und ändern Sie nur das lokale Objekt. Das "echte" Objekt zugegriffen werden durch dieValue
EigenschaftEinen etwas anderen Ansatz ist, dass Sie erstellen einen wrapper, implementiert die gleiche Schnittstelle wie Ihre "realen" Objekts, wodurch dieses Geschenkpapier transparent.
Nun der wrapper kann verwendet werden, als ob es die "echten" Objekt. Sie könnten auch eine erste Instanz von der "wirklichen" Objekt in der wrapper-Konstruktor und entfernen Sie die Initialisierung der
_obj
.InformationsquelleAutor Olivier Jacot-Descombes
Nein, das ist nicht möglich.
Tatsächlich ändern Sie alle Verweise auf ein Objekt, Sie würden eingefroren haben alle threads im Prozess, und der Zugang zu Ihrem register sets und stack. Das ist es, was der garbage collector funktioniert, aber es ist nicht möglich, für normalen code.
Was die Methode wahrscheinlich nicht zu machen, ist eine Tiefe Kopie von einem Objekt auf das andere.
UnityEngine.Object
's sind nicht thread-sicher.Sie sind nicht, und er hat Recht. In der Tat glaube ich, in der Dokumentation ausdrücklich, dass es sich um eine Kopie, die nicht durch einen Verweis.
InformationsquelleAutor Guffa
Wenn es eine custom-Klasse, die Sie verweisen möchten, ich denke, man kann alle Verweise zeigen auf eine Gefälschte Referenz...
Habe ich ein Zuweisungsoperator, so habe ich alle Objekte A als ACs.
Nun, wenn Sie wollen, können Sie die ChangeReference Methode zu schalten, um die neue Referenz..
in C++ würden Sie verwenden, Verweis auf Referenz
Viel Glück
InformationsquelleAutor Tomer W