When assigning an object to another object of the same type, it means that the stack information of the two objects is the same. When you want to change a property of an object and add it to a list, it will be replaced by the last object, and you cannot add a new object. The following two methods can realize the assignment of objects to objects of the same type. The stack information of these two objects is different.
Method 1:
Object must be serialized
public static object DeepClone(object obj) { BinaryFormatter bFormatter = new BinaryFormatter(); MemoryStream stream = new MemoryStream(); bFormatter.Serialize(stream, obj); stream.Seek(0, SeekOrigin.Begin); return bFormatter.Deserialize(stream); }
Test:
[Serializable] class User { public User(){} public int id; public string name; public User(int id, string name) { this.id = id; this.name = name; } } public class test : MonoBehaviour { List<User> users; User user; // Use this for initialization void Start () { users = new List<User>(); user = new User(2,"Floret"); } int b = 5; private void Update() { if (Input.GetKeyDown(KeyCode.Q)) { var a = new User(); a = GameTool.DeepClone(user) as User; a.id = b++; users.Add(a); } } }
Method two:
public static object CopyObject(object obj) { object targetDeepCopyObj; if (obj == null) { Debug.Log("copy obj is null"); } var targetType = obj.GetType(); //Value type if (targetType.IsValueType == true) { targetDeepCopyObj = obj; } //reference type else { targetDeepCopyObj = Activator.CreateInstance(targetType); //Create reference object MemberInfo[] memberCollection = obj.GetType().GetMembers(); foreach (MemberInfo member in memberCollection) { if (member.MemberType == MemberTypes.Field) { FieldInfo field = (FieldInfo)member; object fieldValue = field.GetValue(obj); if (fieldValue is ICloneable) { field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone()); } else { field.SetValue(targetDeepCopyObj, CopyObject(fieldValue)); } } else if (member.MemberType == MemberTypes.Property) { PropertyInfo myProperty = (PropertyInfo)member; MethodInfo info = myProperty.GetSetMethod(false); if (info != null) { object propertyValue = myProperty.GetValue(obj, null); if (propertyValue is ICloneable) { myProperty.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null); } else { myProperty.SetValue(targetDeepCopyObj, CopyObject(propertyValue), null); } } } } } return targetDeepCopyObj; } public static void CopyObject(object source, object target) { var targetType = target.GetType(); if (targetType == null) { targetType = source.GetType(); } //Value type if (targetType.IsValueType == true) { target = source; } //reference type else { if (source == null) { return; } MemberInfo[] memberCollection = source.GetType().GetMembers(); foreach (MemberInfo member in memberCollection) { if (member.MemberType == MemberTypes.Field) { FieldInfo field = (FieldInfo)member; object fieldValue = field.GetValue(source); if (fieldValue is ICloneable) { field.SetValue(target, (fieldValue as ICloneable).Clone()); } else { field.SetValue(target, CopyObject(fieldValue)); } } else if (member.MemberType == MemberTypes.Property) { PropertyInfo myProperty = (PropertyInfo)member; MethodInfo info = myProperty.GetSetMethod(false); if (info != null) { object propertyValue = myProperty.GetValue(source, null); if (propertyValue is ICloneable) { myProperty.SetValue(target, (propertyValue as ICloneable).Clone(), null); } else { myProperty.SetValue(target, CopyObject(propertyValue), null); } } } } } }
Test:
class User { public User(){} public int id; public string name; public User(int id, string name) { this.id = id; this.name = name; } } public class test : MonoBehaviour { List<User> users; User user; // Use this for initialization void Start () { users = new List<User>(); user = new User(2,"Floret"); } int b = 5; private void Update() { if (Input.GetKeyDown(KeyCode.Q)) { var a = new User(); a = GameTool.CopyObject(user) as User; a.id = b++; users.Add(a); } } }
Test result keyu can view users data at breakpoint