C#通過反射實現兩個對象相同屬性值的復制


前言

在寫程序的過程中經常遇到將一個對象中的屬性值賦給另一個對象,一般情況下我們都是一個一個屬性對應賦值,但是這樣過於繁雜,並且當類的屬性發生變化時,還要去修改對應關系。基於這種需求,我寫了一個幫助類,方便大家復制屬性值,有什么不足之處或者需要改進的地方希望大家指出,如有更好的方法還請賜教。

代碼實現

下面就是代碼,已加注釋,不再贅述。
ObjectCopy.cs

/// <summary>
/// 對象屬性值復制
/// </summary>
public class ObjectCopy
{
	/// <summary>
	/// 屬性映射(靜態對象,無需重復建立屬性映射關系,提高效率)
	/// </summary>
	public static Dictionary<string, List<string>> MapDic = new Dictionary<string, List<string>>();
	/// <summary>
	/// S復制到D(創建對象D)
	/// </summary>
	/// <typeparam name="D">輸出對象類型</typeparam>
	/// <typeparam name="S">輸入對象類型</typeparam>
	/// <param name="s">輸入對象</param>
	/// <returns></returns>
	public static D Copy<S, D>(S s) where D : class, new() where S : class, new()
	{
		if (s == null)
		{
			return default(D);
		}
		//使用無參數構造函數,創建指定泛型類型參數所指定類型的實例
		D d = Activator.CreateInstance<D>();
		return Copy<S, D>(s, d);
	}
	/// <summary>
	/// S復制到D(對象D已存在)
	/// </summary>
	/// <typeparam name="D">輸出對象類型</typeparam>
	/// <typeparam name="S">輸入對象類型</typeparam>
	/// <param name="s">輸入對象</param>
	/// <param name="d">輸出對象</param>
	/// <returns></returns>
	public static D Copy<S, D>(S s,D d) where D: class, new() where S : class, new()
	{
		if (s==null||d==null)
		{
			return d;
		}
		try
		{
			var sType = s.GetType();
			var dType = typeof(D);
			//屬性映射Key
			string mapkey = dType.FullName + "_" + sType.FullName;
			if (MapDic.ContainsKey(mapkey))
			{
				//已存在屬性映射
				foreach (var item in MapDic[mapkey])
				{
					//按照屬性映射關系賦值
					//.net 4
					dType.GetProperty(item).SetValue(d, sType.GetProperty(item).GetValue(s, null), null);
					//.net 4.5
					//dType.GetProperty(item).SetValue(d, sType.GetProperty(item).GetValue(s));
				}
			}
			else
			{
				//不存在屬性映射,需要建立屬性映射
				List<string> namelist = new List<string>();
				Dictionary<string, TypeAndValue> dic = new Dictionary<string, TypeAndValue>();
				//遍歷獲取輸入類型的屬性(屬性名稱,類型,值)
				foreach (PropertyInfo sP in sType.GetProperties())
				{
					//.net 4
					dic.Add(sP.Name, new TypeAndValue() { type = sP.PropertyType, value = sP.GetValue(s, null) });
					//.net 4.5
					//dic.Add(sP.Name, new TypeAndValue() { type = sP.PropertyType, value = sP.GetValue(s) });
				}
				//遍歷輸出類型的屬性,並與輸入類型(相同名稱和類型的屬性)建立映射,並賦值
				foreach (PropertyInfo dP in dType.GetProperties())
				{
					if (dic.Keys.Contains(dP.Name))
					{
						if (dP.PropertyType == dic[dP.Name].type)
						{
							namelist.Add(dP.Name);
							//.net 4
							dP.SetValue(d, dic[dP.Name].value, null);
							//.net 4.5
							//dP.SetValue(d, dic[dP.Name].value);
						}
					}
				}
				//保存映射
				if (!MapDic.ContainsKey(mapkey))
				{
					MapDic.Add(mapkey, namelist);
				}
			}
		}
		catch (Exception ex)
		{
			Debug.Write(ex);
		}
		return d;
	}
	/// <summary>
	/// SList復制到DList
	/// </summary>
	/// <typeparam name="D">輸出對象類型</typeparam>
	/// <typeparam name="S">輸入對象類型</typeparam>
	/// <param name="sList">輸入對象集合</param>
	/// <returns></returns>
	public static IQueryable<D> Copy<S, D>(IQueryable<S> sList) where D : class, new() where S : class, new()
	{
		List<D> dList = new List<D>();
		foreach (var item in sList)
		{
			dList.Add(Copy<S, D>(item));
		}
		return dList.AsQueryable();
	}
}
/// <summary>
/// 類型和值
/// </summary>
class TypeAndValue
{
	/// <summary>
	/// 類型
	/// </summary>
	public Type type { get; set; }
	/// <summary>
	/// 值
	/// </summary>
	public object value { get; set; }
}

對於不同的框架有些地方的寫法不同,代碼中也已標注出來。

測試

下面我們創建一個控制台程序去測試一下
Program.cs

class Program
{
	static void Main(string[] args)
	{
		//創建類1的對象
		Person1 p1 = new Person1()
		{
			ID = "10001",
			Name = "人類1號",
			Age = 18,
			Gender = "男"
		};
		Console.WriteLine("p1");
		p1.Write();
		Console.WriteLine("");
		//類1的值給類2(創建類2對象)
		Person2 p21 = ObjectCopy.Copy<Person1, Person2>(p1);
		Console.WriteLine("p21");
		p21.Write();
		Console.WriteLine("");
		//類1的值給類2(類2已存在)
		Person2 p22 = new Person2();
		p22.Address = "中國";
		ObjectCopy.Copy<Person1, Person2>(p1, p22);
		Console.WriteLine("p22");
		p22.Write();
		Console.ReadLine();
	}
}
/// <summary>
/// 測試類1
/// </summary>
class Person1
{
	public string ID { get; set; }
	public string Name { get; set; }
	public int Age { get; set; }
	public string Gender { get; set; }
	public virtual void Write()
	{
		Console.WriteLine("ID:" + this.ID);
		Console.WriteLine("Name:" + this.Name);
		Console.WriteLine("Age:" + this.Age);
		Console.WriteLine("Gender:" + this.Gender);
	}
}
/// <summary>
/// 測試類2
/// </summary>
class Person2: Person1
{
	public string Address { get; set; }
	public override void Write()
	{
		base.Write();
		Console.WriteLine("Address:" + this.Address);
	}
}

輸出結果:

代碼下載

鏈接:http://pan.baidu.com/s/1jIBZ91G 密碼:8z5e


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM