Replace an instance of an object with another in C #

In this matter, I would like to know whether it is possible and how it is possible. This technique would seem like very bad practice, but it seems that the API (UnityEditor) I use does something like this, and I'm just curious.

If there are several references to the same object, is it possible to create an instance of a new object in the same memory slot so that all previous links point to a new object?

I realized that the only possible way to do this is to use unmanaged C ++. Essentially the following happens:

// 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? 

Some, as prefab now points to another object?

Note. Keep in mind that Unity is built on top of Mono.NET styles.

+6
source share
4 answers

Since the state of the object is determined by the values ​​of the fields, you can copy the memory containing the values ​​of the fields from one object to another, effectively "replace":

 public static void Replace<T>(T x, T y) where T : class { // replaces 'x' with 'y' if(x == null) throw new ArgumentNullException("x"); if(y == null) throw new ArgumentNullException("y"); var size = Marshal.SizeOf(typeof(T)); var ptr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(y, ptr, false); Marshal.PtrToStructure(ptr, x); Marshal.FreeHGlobal(ptr); } 

Note that this code requires the [StructLayout(LayoutKind.Sequential)] (or LayoutKind.Explicit ) attribute defined for the class.

+1
source

This can be done if you insert your object into another that is used to access the object.

 class ObjectReference<T> where T : new() { private T _obj = new T(); public void CreateNewObject() { _obj = new T(); } public T Value { get return _obj; } } 

Now you can create several references to an object of type MyObjectReference and change only the local object. The "real" object will be available through the Value property

A slightly different approach is that you create a wrapper that implements the same interface as your "real" object, making the transparency of this flow.

 interface ISomeInterface { string PropertyA { get; set } void MethodB (int x); } class TheRealObject : ISomeInterface { public string PropertyA { get; set } public void MethodB (int x) { Console.WriteLine(x); } } class Wrapper : ISomeInterface { TheRealObject _obj = new TheRealObject(); public string PropertyA { get { return _obj.PropertyA; } set { _obj.PropertyA = value; } } public void MethodB (int x) { _obj.MethodB(x); } public void CreateNewObject() { _obj = new TheRealObject(); } } 

Now the shell can be used as if it were a "real" object. You can also pass the initial instance of the β€œreal” object in the wrapper constructor and remove the _obj initializer.

+5
source

No, It is Immpossible.

To actually change all references to an object, you will have to freeze all threads in the process and gain access to their register sets and stack. This is what the garbage collector does, but it is not possible for regular code.

What the method most likely does is to make a deep copy of one object on another.

+3
source

If this is a custom class that you want to reference, I think you can have all the links to the Fake Reference ...

  • create your class (A)
  • create your class interface (IA)
  • Create a wrapper class based on your interface that simply passes all the calls to the contained object (AC)

I added an assignment operator, so I have all the objects of A as AC.

 class AC:IA { IA ref; AC(IA ref) { this.ref = ref; } public void ChangeReference(IA newRef) { ref = newRef;} public static operator = (IA assignedObj) { return (assignedObject is AC) ? assignedObject : new AC(assignedObj); } // implementation of all methods in A public override string ToString() { return ref.ToString(); } ... } 

Now, if you want, you can use the ChangeReference method to switch everyone to the new Reference.

in c ++ you would use link to link

Good luck

+1
source

Source: https://habr.com/ru/post/919944/


All Articles