zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    WCF中的自定义类中包括自定义枚举类型时出错
    Asp.Net无刷新上传并裁剪头像
    C# 字符串模糊查找
    .NET中如何通过文本框中按回车键进行的提交数据
    关于Firefox、Safari 与IE区别实际应用的一点心得
    ASP.NET 网速慢时候按钮禁止重复提交
    ASP.NET前台代码绑定后台变量方法总结
    验证功能在IE中没问题,在火狐浏览器中无反应
    aspx 后台cs文件动态修改Lable 样式
    asp.net程序调试 连接池和 "Timeout expired"异常
  • 原文地址:https://www.cnblogs.com/ArtlessBruin/p/8126413.html
Copyright © 2011-2022 走看看