在C#中用另一个替换对象实例

Lea*_*yes 10 c# memory pointers reference unity-game-engine

在这个问题中,我想知道是否以及如何做到这一点.这种技术似乎是非常糟糕的做法,但似乎我正在使用的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?
Run Code Online (Sandbox Code Playgroud)

prefab现在如何指向不同的对象?

注意:请记住,Unity是基于Mono的.NET风格构建的

max*_*max 6

由于对象状态由字段值定义,因此您可以将包含字段值的内存从一个对象复制到另一个对象,从而有效地“替换”它:

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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,此代码需要为类定义[StructLayout(LayoutKind.Sequential)](或LayoutKind.Explicit)属性。


Oli*_*bes 5

如果将对象嵌入到用于访问对象的另一个对象中,则可以这样做.

class ObjectReference<T>
   where T : new()
{
    private T _obj = new T();

    public void CreateNewObject()
    {
        _obj = new T();
    }

    public T Value { get return _obj; }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以创建对类型对象的多个引用,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();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,包装器可以像使用"真实"对象一样使用.您还可以在包装器的构造函数中传递"真实"对象的初始实例,并删除初始化器_obj.