- Home /
Deep cloning a list with elements that reference other elements in the list.
Hi, I have an abstract class 'Command' deriving from ScriptableObject in my custom Node-based Editor. Each Command contains a List of Command which holds a reference to all the Commands that should be run immediately after this Command. All of these Commands are held in a list, and are saved to a MonoBehaviour using Deep Cloning to prevent the saved reference referring to the changing reference.
public static List<Command> CloneCommandList(List<Command> oldCommands)
{
List<Command> newCommands = new List<Command>();
for (int i = 0; i < oldCommands.Count; i++)
{
newCommands.Add(Instantiate(oldCommands[i]));
}
return newCommands;
}
This saves the external list, but does not preserve the Lists inside of Command, as the references do not point to the deep cloned version. I do have an idea in mind about finding where the references point to in each list and applying them after the clone, but it's too late to code here and I think it will take a while, so if anyone has a shortcut/idea, please let me know :)
Thank you, Tom
Answer by Bunny83 · Mar 03, 2017 at 10:21 PM
Well, if the sub-commands are guaranteed to be unique (so no cross referencing or circular referencing) you can simply replace your Instantiate with a recursive function that first clones (instantiates) the passed command and in addition iterates the list of that command and recursively clones all commands down the line.
Of course a circular command reference would send the code in an infinite recursion and would most likely crash with a stackoverflow. Also if two commands reference the same sub command after cloning each would have a seperate identical command. If you want to prevent those problems you may want to use a Dictionary<Command, Command>
as recursion context. You would simply keep track of each instantiate you do. So for each old Command you instantiate you add (oldCommand, instantiatedCommand)
to the dictionary. Before instantiating you first check the dictionary if the command has already been instantiated and if so, just return the new instance that is stored in the dictionary. This will work even with circular or cross references.
Thank you, much better implementation than the hack I was thinking of!