在C#中用另一个替换对象实例
在这个问题中,我想知道是否以及如何做到这一点。 这种技术似乎是非常糟糕的做法,但似乎我正在使用的API(UnityEditor)正在做这样的事情,我只是很好奇。
如果对同一对象有多个引用,是否可以将新对象实例化到同一个内存槽中,以便所有先前的引用都指向新对象?
我发现唯一可行的方法是使用非托管C ++。 基本上发生以下情况:
// 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?
一些prefab
现在如何指向不同的对象?
注意:请记住,Unity是基于Mono的.NET风格构建的
由于对象状态由字段值定义,因此您可以将包含字段值的内存从一个对象复制到另一个对象,从而有效地“替换”它:
public static void Replace(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); }
请注意,此代码需要为类定义[StructLayout(LayoutKind.Sequential)]
(或LayoutKind.Explicit
)属性。
如果将对象嵌入到用于访问对象的另一个对象中,则可以这样做。
class ObjectReference where T : new() { private T _obj = new T(); public void CreateNewObject() { _obj = new T(); } public T Value { get return _obj; } }
现在,您可以创建对MyObjectReference
类型的对象的多个引用,并仅更改本地对象。 可以通过Value
属性访问“真实”对象
稍微不同的方法是创建一个包装器,它实现与“真实”对象相同的接口,从而使这种包装透明。
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(); } }
现在,包装器可以像使用“真实”对象一样使用。 您还可以在包装器的构造函数中传递“真实”对象的初始实例,并删除_obj
的初始化_obj
。
不,那是不可能的。
要实际更改对象的所有引用,您必须冻结进程中的所有线程,并访问它们的寄存器集和堆栈。 这就是垃圾收集器的作用,但是常规代码不可能。
该方法最有可能的做法是将一个对象的深层副本复制到另一个对象上。
如果它是您要引用的自定义类,我认为您可以将所有引用指向假冒参考…
- 创建你的课程(A)
- 创建你的类接口(IA)
- 根据您的接口创建一个包装类,它只传递对包含对象的所有调用(AC)
我添加了一个赋值运算符,所以我将所有A对象作为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(); } ... }
现在,如果需要,可以使用ChangeReference方法将所有内容切换到新的Reference。
在C ++中,您将使用Reference to Reference
祝你好运