Unity Class deep copy problem analysis

deep copy

foreword

In a Unity project we are facing a problem of reading a data table and deep copying the class. The specific situation is this: we need to read the data of the characters from the data table, but during the battle, the data of the characters will continue to change. Therefore, we need a data class to store character data, and hope to create a copy for combat without modifying the original data table.

In order to realize this logic, we take the following steps: First, we deserialize the data table in Json or Xml format into the original data class, and use the tool to perform the deserialization operation. We then do a deep copy of the original data class, creating a copy of the combat data class. In this way, we can not only use the data in the original data table, but also modify the combat data class during the battle without affecting the function of the original data table.

The advantage of this is that we can use the battle data class independently in the battle without affecting the integrity of the original data table. At the same time, through deep copying, we ensure that the battle data class is a brand new object that can be modified independently of the original data class, avoiding problems caused by object references.

Common solutions

1. Manually copy fields

If the class has few fields and simple structure, you can manually copy each field to create a new object. This requires copying each field of the class one by one, making sure that the value of the field is copied and not a reference.

public class MyClass
{
    
    
    public int myInt;
    public string myString;

    public MyClass DeepCopy()
    {
    
    
        MyClass newObject = new MyClass();
        newObject.myInt = myInt;
        newObject.myString = myString;
        return newObject;
    }
}

2. Use serialization tools

Use JsonUtility, MsgPack, Protobuf and other tool libraries for serialization and deserialization functions, and can handle more complex class structures. A deep copy is achieved by serializing an object into a byte stream and then deserializing it into a new object.
For example, the following:

TIP: Don't use this, this is my current project, there is no corresponding class and it can't be used

    /// <summary>
    /// Json文件转实体类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <returns></returns>
    public static List<T> JsonToObject<T>(string value) where T : ConfigJsonBase
    {
    
    
        List<T> lst = new List<T>();
        var test = JsonConvert.DeserializeObject<ConfigJsonContainer>(value, settings);
        test.CopyListToDic();
        foreach (var item in test.dataMap)
        {
    
    
            T line1 = (T)item.Value;
            lst.Add(line1);
        }
        return lst;
    }

It is equivalent to serializing from the table again to get a brand new copy

3. Use the Instantiate method (only for MonoBehaviour)

How to use UnityEngine.Object.Instantiate: If you need to copy the Unity engine's GameObjector MonoBehaviour, you can use Instantiatethe method to create a copy of them. This method creates a brand new instance, including all components and properties, and decouples them from the original object.

public class CopyExample : MonoBehaviour
{
    
    
    public GameObject originalObject;
    private GameObject copiedObject;

    public void PerformCopy()
    {
    
    
        copiedObject = Instantiate(originalObject);
        // 对复制对象进行进一步操作...
    }
}

4. Rewrite operator assignment

The following case is &to create a new class and assign values ​​to all fields by overriding the operator.
When creating a new object by using &an operator, you can trigger overloading of the operator by passing the original object as the first argument to the operator and omitting the second argument. The new newCardobject will have the same field values ​​as the original object.

This method relies on the rewriting of operators, and when using them, you need to pay attention to the semantics and correct usage of operators. Also, since the & operator is usually associated with a bitwise AND operation, rewriting it to create a new object may make the code less readable. Therefore, in actual use, it is recommended to choose carefully whether to use this method of rewriting operators to ensure the clarity and maintainability of the code.

public class CfgCardProperties : ConfigJsonBase
{
    
    
    public string _CardName;
    public List<string> _CardIconPath;
    public bool _IsShowCardUnder;

    public static CfgCardProperties operator &(CfgCardProperties card, CfgCardProperties cfg)
    {
    
    
        CfgCardProperties newCard = new CfgCardProperties();
        card.ID = cfg.ID;
        card._CardName = cfg._CardName;
        card._CardIconPath = cfg._CardIconPath != null ? new List<string>(cfg._CardIconPath) : null;
        return newCard;
    }
}

usage is

var cfg = new CfgCardProperties();
cfg &= originalCfgs[i];

5. Use the copy function provided in Visual Scripting (recommended)

In Unity Visual Scripting, CloneViaFakeSerializationnodes can be used to implement deep copies of objects. Available in Bolt or other Unity visual scripting tools, this node serializes and deserializes an object to create a copy of it.

CloneViaFakeSerializationNode works as follows:

  1. Serialize the object to be cloned, converting it to a byte stream.
  2. Deserialize the byte stream into a new object.

In the above example, only one line is needed to implement the deep copy of the class

using Unity.VisualScripting;

cfg= originalCfgs[i].CloneViaFakeSerialization();

おすすめ

転載: blog.csdn.net/a71468293a/article/details/131205203