c# - 列表的深拷贝

标签 c# list unity3d deep-copy

这应该是一个相当简单的问题,但我已经尝试了几种方法,但结果总是一样。

我正在尝试将包含游戏对象的列表复制到另一个列表中。问题是我似乎正在复制引用,因为对原始列表的游戏对象所做的任何更改也会影响新列表中的那些,这是我不想发生的事情。根据我的阅读,我正在做浅拷贝而不是深拷贝,所以我尝试使用以下代码来克隆每个对象:

public static class ObjectCopier
    {
        /// <summary>
        /// Perform a deep Copy of the object.
        /// </summary>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>The copied object.</returns>
        public static GameObject Clone<GameObject>(GameObject source)
        {

            if (!typeof(GameObject).IsSerializable)
            {
                throw new ArgumentException("The type must be serializable ", "source: " + source);
            }

            // Don't serialize a null object, simply return the default for that object
            /*if (Object.ReferenceEquals(source, null))
            {
                return default(GameObject);
            }*/

            IFormatter formatter = new BinaryFormatter();
            Stream stream = new MemoryStream();
            using (stream)
            {
                formatter.Serialize(stream, source);
                stream.Seek(0, SeekOrigin.Begin);
                return (GameObject)formatter.Deserialize(stream);
            }
        }
    }

我收到以下错误:

ArgumentException: The type must be serializable Parameter name: source: SP0 (UnityEngine.GameObject) ObjectCopier.Clone[GameObject] (UnityEngine.GameObject source) (at Assets/Scripts/ScenarioManager.cs:121)

上面贴出的函数在这里调用:

    void SaveScenario(){
        foreach(GameObject obj in sleManager.listOfSourcePoints){
            tempObj = ObjectCopier.Clone(obj);

            listOfScenarioSourcePoints.Add(tempObj);
            Debug.Log("Saved Scenario Source List Point");
        }
        foreach(GameObject obj in sleManager.listOfDestPoints){
            tempObj = ObjectCopier.Clone(obj);
            listOfScenarioDestPoints.Add(tempObj);
            Debug.Log("Saved Scenario Dest List Point");
        }
    }

    void LoadScenario(){
        sleManager.listOfSourcePoints.Clear();
        sleManager.listOfDestPoints.Clear ();
        foreach(GameObject obj in listOfScenarioSourcePoints){
            tempObj = ObjectCopier.Clone(obj);
            sleManager.listOfSourcePoints.Add(tempObj);
            Debug.Log("Loaded Scenario Source List Point");
        }
        foreach(GameObject obj in listOfScenarioDestPoints){
            tempObj = ObjectCopier.Clone(obj);
            sleManager.listOfDestPoints.Add(tempObj);
            Debug.Log("Loaded Scenario Dest List Point");
        }
    }

现在,原始列表在这里创建:

if (child.name == "DestinationPoints")
{
     parentDestinationPoints = child.gameObject;
     foreach (Transform grandChildDP in parentDestinationPoints.transform)
     {
          //Debug.Log("Added DP object named: " + grandChildDP.name);
          tempObj = grandChildDP.gameObject;
          listOfDestPoints.Add(tempObj);
          tempObj.AddComponent<DestinationControl>();
          tempObj.transform.renderer.material.color = Color.white;
     }
}

// Hide all SourcePoints in the scene
if (child.name == "SourcePoints")
{
    parentSourcePoints = child.gameObject;
    foreach (Transform grandChildSP in parentSourcePoints.transform)
    {
         tempObj = grandChildSP.gameObject;
         listOfSourcePoints.Add(tempObj);
         tempObj.transform.renderer.enabled = false;
    }
}

这个“tempObj”有 [SerializeField] 属性,所以我一定是遗漏了一些东西。任何帮助将不胜感激。

编辑:忘了说,这个应用程序是在 Unity3D 中。

最佳答案

我认为您需要使用 [Serializable] 属性标记您尝试克隆的类 GameObject。我也会使克隆方法通用,这样它就不仅限于类型:

/// <summary>
/// Creates a deep clone of an object using serialization.
/// </summary>
/// <typeparam name="T">The type to be cloned/copied.</typeparam>
/// <param name="o">The object to be cloned.</param>
public static T DeepClone<T>(this T o)
{
    using (MemoryStream stream = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, o);
        stream.Position = 0;
        return (T)formatter.Deserialize(stream);
    }
}

希望对您有所帮助。


编辑。也许没有序列化的深度复制使用类似的东西

class A
{
    // copy constructor
    public A(A copy) {}
}

// A referenced class implementing 
class B : IDeepCopy
{
    object Copy() { return new B(); }
}

class C : IDeepCopy
{
    A A;
    B B;
    object Copy()
    {
        C copy = new C();

        // copy property by property in a appropriate way
        copy.A = new A(this.A);
        copy.B = this.B.Copy();
     }
}

我也刚找到Copyable它使用反射来提供对象的深拷贝。再次,我希望这对您有所帮助...

关于c# - 列表的深拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22531461/

相关文章:

c# - 窗体上的 Mouseenter 和 Mouseleave

c# - foreach 循环是否正确处理列表长度的变化?

c# - Zenject 游戏对象注入(inject)

unity3d - Unity给原始网格添加顶点

c# - .net 中是否存在将 JSON 解析为 Dictionary<String,Object> 的现有库?

c# - 这些列目前没有唯一值

c# - WebClient 很慢

list - LISP 如何从列表中删除特定索引处的元素

scala - 转置大小不均的列表

c# - int[,] 数组与 Dictionary<> 的效率比较,用于不断更新