图片 1

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);
    }
}

输出结果:
图片 1

代码下载

链接:http://pan.baidu.com/s/1jIBZ91G 密码:8z5e