zoukankan      html  css  js  c++  java
  • 反射 实现不同模型相同属性赋值 第二集(automapper)

    前言: 两年前写过一个 反射实现不同模型相同属性赋值  只能简单的实现两个model 相同属性名,相同类型赋值

    最近又遇到这个问题,需要对相同属性名或者指定属性名 不同类型(复杂对象,如:List<class1> 到list<class2>)对象赋值,所有之前的代码就不能用了

    花了点时间把这个代码给完善了点点


     需求:1.对不同model中的相同属性名赋值 如:Class1中Name 赋值到 Class2中Name

           2.对不同model中的不同属性名赋值 如:Class1中Name 赋值到 Class2中Uname

           3.对不同model中的相同属性名(集合对象)赋值,集合对象赋值要分4种情况

         3.1.两个model中集合对象都是List集合  如:Class1中List<User1> 赋值到 Class2中List<User2>

         3.2.两个model中集合对象都是数组(Array)  如:Class1中User1[] 赋值到 Class2中User2[]

                 3.3.一个model中是List,一个里面是Array  如:Class1中List<User1> 赋值到 Class2中User2[]

                 3.4.一个model中是Array,一个是List  如:Class1中User1[] 赋值到 List<User2>
    大概需求就是如上,不考虑基础数据类型转换,如:Class1中Time(数据类型String)  到 Class2中Time(数据类型Datetime)

    这里不再对需求1进行讨论,可以直接使用两年前写的


    话不多说,先贴代码,再解释.

    1.常量

    private static readonly string ListTypeName = typeof (List<>).Name;  //用于判定是否是List集合

    2.主函数

    /// <summary>
    /// 模型赋值
    /// </summary>
    /// <param name="source">数据源模型</param>
    /// <param name="target">目标模型</param>
    /// <param name="pars">数据源模型指定属性值 赋值 到目标模型指定属性,例:Key=Name,Value=Uname 把数据模型Name属性赋给目标模型Uname</param>
    public static void CopyModel(object source, object target, Dictionary<string, string> pars)
    {
        //获取Type
        Type ttarget = target.GetType();
        Type tsource = source.GetType();
    
        //根据 数据模型 来对 目标模型 赋值
        //循环数据模型所有公共属性
        foreach (var sourceAttr in tsource.GetProperties())
        {
            //pars.ContainsKey(sourceAttr.Name) 得到不同属性名,用来实现 数据模型Name属性赋给目标模型Uname
            PropertyInfo targetAttr = ttarget.GetProperty(pars.ContainsKey(sourceAttr.Name) ? pars[sourceAttr.Name] : sourceAttr.Name);//获取目标模型属性Name==数据模型属性Name(得到目标属性)
            if (targetAttr == null)  //为null标识目标模型中没有该属性,进入下次循环
                continue;
            try
            {
                //获取两个model属性类型
                var targetProType = targetAttr.PropertyType;
                var sourceProType = sourceAttr.PropertyType;
                //list->list 判断两个属性类型是否为list
                if (targetProType.Name == ListTypeName && sourceProType.Name == ListTypeName) 
                {
                    var miValue = (IList)sourceAttr.GetValue(source, null);  //得到数据模型中该属性的数据,直接转为IList
                    CopeToList(miValue, target, pars, targetAttr);  //调用赋值
                    return;
                }
                //array->array 判断两个属性类型是否为array
                if (targetProType.IsArray && sourceProType.IsArray)
                {
                    var miValue = (Array)sourceAttr.GetValue(source, null); //得到数据模型中该属性的数据,直接转为Array
                    CopyToArray(miValue, miValue.Length, target, pars, targetAttr);  //调用赋值
                    return;
                }
                //list->array 当数据属性类型为List 目标属性类型为Array
                if (targetProType.IsArray && sourceProType.Name == ListTypeName)
                {
                    var miValue = (IList)sourceAttr.GetValue(source, null);  //得到数据模型中该属性的数据,直接转为IList
                    CopyToArray(miValue, miValue.Count, target, pars, targetAttr);  //调用赋值
                    return;
                }
                //array->list 当数据属性类型为Array 目标属性类型为List
                if (targetProType.Name == ListTypeName && sourceProType.IsArray)
                {
                    var miValue = (Array)sourceAttr.GetValue(source, null);  //得到数据模型中该属性的数据,直接转为Array
                    CopeToList(miValue, target, pars, targetAttr);  //调用赋值
                    return;
                }
                //基础数据类型赋值
                var s = sourceAttr.GetValue(source, null);
                targetAttr.SetValue(target, s, null);
            }
            catch
            {
            }
        }
    }

    3.CopeToList

    /// <summary>
    /// 集合数据赋值 赋值到List
    /// </summary>
    /// <param name="data">数据集合</param>
    /// <param name="target">目标模型</param>
    /// <param name="pars">数据源模型指定属性值 赋值 到目标模型指定属性</param>
    /// <param name="targetAttr">目标属性</param>
    private static void CopeToList(IEnumerable data, object target, Dictionary<string, string> pars, PropertyInfo targetAttr)
    {
        if (data == null)
            return;
        //获取目标属性类型
        var targetProType = targetAttr.PropertyType;
    
        //得到目标属性值
        var desValue = (IList)targetAttr.GetValue(target, null);
        if (desValue == null)  //如果List为null 需要new List<T>();
        {
            var newlist = Activator.CreateInstance(targetProType);  //根据目标属性类型实例化List,如:目标属性为List<Class1>
            targetAttr.SetValue(target, newlist, null);  //把newlist写入(赋值)目标属性
            desValue = (IList)targetAttr.GetValue(target, null);  //再次获取目标属性值
        }
        var desMethod = targetProType.GetMethod("Add");  //获取到List.Add方法
        var modelType = targetProType.GetGenericArguments()[0];  //获取List<T>中 T的类型
        foreach (var v in data) //循环数据集合
        {
            var model = Activator.CreateInstance(modelType);  //创建T实例
            CopyModel(v, model, pars); //调用模式赋值
            desMethod.Invoke(desValue, new[] { model });  //调用List.Add方法,将数据对象Add到目标属性(List)中
        }
    }

    4.CopyToArray

    /// <summary>
    /// 集合数据赋值 赋值到数组(Array)
    /// </summary>
    /// <param name="data">数据集合</param>
    /// <param name="count">数据条数(由于IEnumerable不方便获取数据条数,所有这里通过外面传入参数)</param>
    /// <param name="target">目标模型</param>
    /// <param name="pars">数据源模型指定属性值 赋值 到目标模型指定属性</param>
    /// <param name="targetAttr">目标属性</param>
    private static void CopyToArray(IEnumerable data,int count, object target, Dictionary<string, string> pars, PropertyInfo targetAttr)
    {
        if (data == null)
            return;
        //获取目标属性类型
        var targetProType = targetAttr.PropertyType;
                
        var arr = Type.GetType(targetProType.FullName);  //根据目标数组对象实例化心的数组对象
        var newarr = (Array)arr.InvokeMember("Set", BindingFlags.CreateInstance, null, arr, new object[] { count }); //调用数组Set方法设置数组长度,长度为count
        var modelType = Type.GetType(targetProType.FullName.Replace("[]", ""));  //获取数组元素类型
        int c = 0;  //用来为数组数据位置定位  
        foreach (var v in data)
        {
            var model = Activator.CreateInstance(modelType);  //实例化数组元素对象
            CopyModel(v, model, pars);  //调用赋值
            newarr.SetValue(model, c);  //用SetValue方法进行赋值
            c++;
        }
        targetAttr.SetValue(target, newarr, null); //将新数组直接赋值到目标属性
    }

    解释

    上面代码注释应该还算比较详细吧,下面就来列举上面代码的使用

    需求1.这个就不举例子了,应该很好理解

    需求2.

    model:

    public  class User1
    {
        public string Name{ get; set; }
    }
    
    public  class User2
    {
        public string Uname { get; set; }
    }
    View Code

    用法:

    User1 u1 = new User1 {Name="tom"}
    User2 u2 = new User2 ();
    Dictionary<string, string> dic = new Dictionary<string, string>();
    dic.Add("Name","Uname")
    CopyModel(u1,u2, dic);

    需求3.1.
    model:

    public  class User1
    {
        public List<Test> Test { get; set; }
    }
    
    public  class User2
    {
        public List<Test2> Test { get; set; }
    }
    
    public class Test
    {
        public string Name { get; set; }
    }
    public class Test2
    {
        public string Name { get; set; }
    }
    View Code

    用法:

    User1 u1 = new User1 ();
    u1.Test = new List<Test>();
    u1.Test.Add(new Test { Name = "11"});
    u1.Test.Add(new Test { Name = "22" });
    u1.Test.Add(new Test {Name = "33"});
    User2 u2 = new User2();
    
    Dictionary<string, string> dic = new Dictionary<string, string>();
    CopyModel(u1,u2, dic);

    需求3.2

    model:

    public  class User1
    {
        public Test[] Test { get; set; }
    }
    
    public  class User2
    {
        public Test2[] Test { get; set; }
    }
    View Code

    用法:同上

    需求3.3:

    model:

    public  class User1
    {
        public List<Test> Test { get; set; }
    }
    
    public  class User2
    {
        public Test2[] Test { get; set; }
    }
    View Code

    用法:同上

    需求3.4:

    public  class User1
    {
        public Test2[] Test { get; set; }
    }
    
    public  class User2
    {
        public List<Test> Test { get; set; }
    }
    View Code

    同法:同上


    总结:大致需求就是解决上述模型赋值问题,此方法由于赋值调用自身,可以实现无限下级模型赋值 如:User1.Test为复杂对象集合,Test类中也有复杂集合对象,无限让下执行

       对与复杂集合内不同属性赋值也通过Dictionary传入, 如:User1.Test中Test.Name 赋值到Test2.Uname

    我不晓得我表述清楚没有,反正大家慢慢看吧(我的错别字也是不太多,别介意→_→ ) 

    原帖地址:http://www.cnblogs.com/jio92/p/CopyModel.html

  • 相关阅读:
    第十二讲 Web 服务的创建和使用
    第十七讲 ASP.NET安全性
    第九讲 水晶报表的使用
    第十五讲 数据集的使用方法和技巧
    第十六讲 调试和跟踪ASP.NET应用程序
    第十讲 ASP.NET程序的部署
    第十四讲 ADO.NET数据操作
    第十八讲 Web服务器控件使用
    【笔记】java多线程 2 五种状态
    【笔记】数据库模式
  • 原文地址:https://www.cnblogs.com/jio92/p/CopyModel.html
Copyright © 2011-2022 走看看