C#中物件copy前後比對常見錯誤

 
有時可能會將一些表單資料封裝成DTO或者來自EF某張表的record entity
剛好又涉及到要寫複製資料功能進行局部欄位資料異動時候
就會時常發生連動到舊物件資料的問題


有問題寫法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Program
{
	public static void Main()
	{
		Person person1 = new Person();
		person1.Age=23;
		person1.Name="Amy";
		Console.WriteLine(String.Format("person1 name:{0} / Age:{1}",person1.Name,person1.Age));
		Person person2 = person1;
		person2.Name = "Ted";
		Console.WriteLine(String.Format("person1 name:{0} / Age:{1}",person1.Name,person1.Age));
		Console.WriteLine(String.Format("person2 name:{0} / Age:{1}",person2.Name,person2.Age));
		Console.ReadLine(); 
	}
}



會觀察到物件複製寫法不對只有異動person2的Name也連動到person1的Name

第一種修正法.重新new並指定欄位

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Program
{
	public static void Main()
	{
		Person person1 = new Person();
		person1.Age=23;
		person1.Name="Amy";
		Console.WriteLine(String.Format("person1 name:{0} / Age:{1}",person1.Name,person1.Age));
		//Person person2 = person1;
		//第一種.
		Person person2 = new Person(){Name=person1.Name,Age=person1.Age};
		person2.Name = "Ted";
		Console.WriteLine(String.Format("person1 name:{0} / Age:{1}",person1.Name,person1.Age));
		Console.WriteLine(String.Format("person2 name:{0} / Age:{1}",person2.Name,person2.Age));
		Console.ReadLine(); 
	}
}


第二種修正法.透過反射

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Reflection;
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Program
{
	public static void Main()
	{
		Person person1 = new Person();
		person1.Age=23;
		person1.Name="Amy";
		Console.WriteLine(String.Format("person1 name:{0} / Age:{1}",person1.Name,person1.Age));
		//Person person2 = person1;
		//第一種.
		//Person person2 = new Person(){Name=person1.Name,Age=person1.Age};
		
		Type myType = person1.GetType();
		Person person2 = (Person)System.Activator.CreateInstance(myType);
		PropertyInfo[] properties = myType.GetProperties();
		foreach (var property in properties)
        {
            if (property.CanWrite)
            {
                property.SetValue(person2, person1.GetType().GetProperty(property.Name).GetValue(person1, null), null);
            }
        }

		person2.Name = "Ted";
		Console.WriteLine(String.Format("person1 name:{0} / Age:{1}",person1.Name,person1.Age));
		Console.WriteLine(String.Format("person2 name:{0} / Age:{1}",person2.Name,person2.Age));
		Console.ReadLine(); 
	}
}


更省code寫法就是包成extension method

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Common.CustomExtension
{
    public static class DeepCopyExtension
    {
        public static T GetDeepCopy<T>(this T value)
        {
            Type myType = value.GetType();
            T copyObj = (T)System.Activator.CreateInstance(myType);
            PropertyInfo[] properties = myType.GetProperties();
            foreach (var property in properties)
            {
                if (property.CanWrite)
                {
                    property.SetValue(copyObj, value.GetType().GetProperty(property.Name).GetValue(value, null), null);
                }
            }
            return copyObj;
        }
    }
}


之後只要使用.GetDeepCopy()就可了
Person person2 = person1.GetDeepCopy();
person2.Name = "Ted";



留言

這個網誌中的熱門文章

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header

經得起原始碼資安弱點掃描的程式設計習慣培養(三)_7.Cross Site Scripting(XSS)_Stored XSS_Reflected XSS All Clients

(2021年度)駕訓學科筆試準備題庫歸納分析_法規是非題