Duplicating a [SerializeReference] property?
I'm building an editor tool that involves a graph with nodes, and a custom Editor. I'm utilizing the [SerializeReference] attribute for the nodes, which has worked really well thus far, until I wanted to duplicate a node. That is, create a new node with all the same values as the previous node. Here are some things I've tried:
- Duplicating the element in the list of nodes. This simply creates another reference to the same node object.
- Using BinaryFormatter to create a deep copy of the node, and assigning that to the new node. This doesn't seem to work well with some built-in Unity classes like Vector2, and threw some errors.
- Creating a shallow copy with MemberwiseClone(). This was the closest I've gotten, however reference types, like Lists, were not cloned, and would reference the same List. So if I changed the list on one node, it would change on the other as well.
One thing to note is that I cannot manually go through each value in the node and assign them on the new node, because there are many derived versions of the nodes, and I do not want to implement a sort of .Clone() function on each child class.
Any thoughts?
Answer by minhluongneo · Jan 09 at 05:36 PM
First way: use reflection to iterate over all public or private variables that have attribute [SerializeField] (Remember to ignore the public variable with attribute [NonSerialized]) Because when using [SerializeReference] you can get exactly the derived type of node, instead of the base type. But be careful, because reflection also causes some performance problems if used in build.
Second way: Use a ScriptableObject as a clone machine
//NodeCloner is custom your class
NodeCloner nodeCloner = ScriptableObject.CreateInstance<NodeCloner>();//You can cache it
nodeCloner.nodeData = yourNodeData;
NodeCloner newNodeCloner = ScriptableObject.Instantiate(nodeCloner);
var newNodeData = newNodeCloner.nodeData;
However, as for performance in the build vs. reflection, I haven't tested it yet.
Performance isn't an issue, as this is an editor tool, but thanks for looking out anyway!
The ScriptableObject cloner worked brilliantly, thanks for this really great idea!! The note I'll leave for anyone else looking to solve this issue, is to make sure the nodeData field is also marked as [SerializeReference], otherwise the new copied node will only be of the base node class.
Cheers!