How to make a deep copy instead of a shallow one?

Hi everyone, so as of right now I am making a shallow copy of an item in a list. When I click on this item in game, a copy is made of it and that copy is put in another list. The problem is, when I click on this item more than once, I want each individual copy of this original item to still have different elements. Since a shallow copy is being made right now, each clone is exactly the same… which is not what I want. I am pretty sure the way to do this is to create a deep copy instead, but I don’t know how to change my code to be a deep copy.

To be more specific, I want the time I create each copied item to be different on each one. So when the first time the item is copied, the time on copy1 is 1:00. The second time the item is copied, the time on copy2 is 1:05. That sort of thing. Here is my code below:

[System.Serializable]
public class Item
{
	public string activityName;
	public Sprite icon;
	public float Productivity = 1f;
	public float Social = 1f;
	public float Health = 1f;
	public float Fun = 1f;

	public string dateButtonAdded;
	public string timeAdded;

	public Sprite checkMark;
}

	public void Setup(Item currentItem, ActivityScrollList currentScrolllist){

		item = currentItem;

		nameLabel.text = item.activityName;
		iconImage.sprite = item.icon;

		prodValue.text = item.Productivity.ToString ();
		socValue.text = item.Social.ToString ();
		healthValue.text = item.Health.ToString ();
		funValue.text = item.Fun.ToString ();

		checkMark.sprite = item.checkMark;

		scrollList = currentScrolllist;

	}

I create this items through a simple object pool. I got the code for this from a Unity tutorial. Here is the code for the object pool:

// A very simple object pooling class
public class SimpleObjectPool : MonoBehaviour
{
	
	// the prefab that this object pool returns instances of
	public GameObject prefab;
	// collection of currently inactive instances of the prefab
	private Stack<GameObject> inactiveInstances = new Stack<GameObject>();


	// Returns an instance of the prefab
	public GameObject GetObject() 
	{
		GameObject spawnedGameObject;

		// if there is an inactive instance of the prefab ready to return, return that
		if (inactiveInstances.Count > 0) 
		{
			// remove the instance from the collection of inactive instances
			spawnedGameObject = inactiveInstances.Pop();
		}
		// otherwise, create a new instance
		else 
		{
			spawnedGameObject = (GameObject)GameObject.Instantiate(prefab);

			// add the PooledObject component to the prefab so we know it came from this pool
			PooledObject pooledObject = spawnedGameObject.AddComponent<PooledObject>();
			pooledObject.pool = this;
		}

		// put the instance in the root of the scene and enable it
		spawnedGameObject.transform.SetParent(null);
		spawnedGameObject.SetActive(true);

		// return a reference to the instance
		return spawnedGameObject;
	}

	// Return an instance of the prefab to the pool
	public void ReturnObject(GameObject toReturn) 
	{
		PooledObject pooledObject = toReturn.GetComponent<PooledObject>();

		// if the instance came from this pool, return it to the pool
		if(pooledObject != null && pooledObject.pool == this)
		{
			// make the instance a child of this and disable it
			toReturn.transform.SetParent(transform);
			toReturn.SetActive(false);

			// add the instance to the collection of inactive instances
			inactiveInstances.Push(toReturn);
		}
		// otherwise, just destroy it
		else
		{
			Debug.LogWarning(toReturn.name + " was returned to a pool it wasn't spawned from! Destroying.");
			Destroy(toReturn);
		}
	}
}

// a component that simply identifies the pool that a GameObject came from
public class PooledObject : MonoBehaviour
{
	public SimpleObjectPool pool;
}

So basically I am unsure of how to change my code to be able to create a deep copy instead. Any help on how to do this is greatly appreciated.

The difference between the shallow and deep copy are not just copying the references and value types of an object’s fields, but in the case of reference types, creating brand new objects and populating those with copies of its properties, and recursively.

You can provide a DeepCopy method and create a new instance of your object, then copy over simple properties, while reference types need to have new instances created. Because of the shallow copy you are seeing, your variables such as nameLabel, iconImage, prodValue, etc. are just copying the references over to the new object and the data which they contain will be the same between all objects.

It appears that several types in Unity provide an Instantiate<> method which can take a reference to an existing type and clone it for you. In the case of simple types like bool, float, string, etc. it’s a straight copy of the properties, for things like Image, on the other hand, require the instantiation.

Here is an example of something that uses this technique:

public class Item {

    float someValue;
    string someString;
    bool someBoolean;
    Image iconImage;

    public Item DeepCopy()
    {
        Item sc = new Item();

        sc.someValue = this.someValue;
        sc.someString = this.someString;
        sc.someBoolean = this.someBoolean;
        sc.iconImage = Image.Instantiate<Image>(this.iconImage);

        return sc;
    }
}

One other thing, if you are working with pooled objects and do not want to create a new instance, then you can overload (or replace) your DeepCopy() method and pass a parameter which is a reference to your pooled object. It would then look something like the following (item still returned as a convenience):

    public Item DeepCopy(Item po)
    {
        po.someValue = this.someValue;
        po.someString = this.someString;
        po.someBoolean = this.someBoolean;
        po.iconImage = Image.Instantiate<Image>(this.iconImage);

        return po;
    }