列表的深层副本

问题描述 投票:5回答:3

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

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

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:类型必须是可序列化的参数名称:source:SP0(UnityEngine.GameObject)ObjectCopier.Clone [GameObject](UnityEngine.GameObject source)(在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。

c# list unity3d deep-copy
3个回答
2
投票

我认为您需要使用GameObject属性标记您尝试克隆的类[Serializable]。我还将克隆方法设为通用,以便它不限于类型:

/// <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,它使用反射来提供对象的深层副本。再次,我希望这有一些用处......


0
投票

在Unity中使用Instantiate创建对象的完整副本,如下所述:http://docs.unity3d.com/Documentation/ScriptReference/Object.Instantiate.html?from=MonoBehaviour

var clone = Object.Instantiate(source);

0
投票

我认为我过于复杂化了事情,最终在XML文件中保存了我需要的值(游戏对象位置)(无论如何必须在某些时候执行)。谢谢你的帮助。

© www.soinside.com 2019 - 2024. All rights reserved.