反射 实现不同模型相同属性赋值 第二集(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()[]; //获取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 = ; //用来为数组数据位置定位
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; }
}
用法:
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; }
}
用法:
User1 u1 = new User1 ();
u1.Test = new List<Test>();
u1.Test.Add(new Test { Name = ""});
u1.Test.Add(new Test { Name = "" });
u1.Test.Add(new Test {Name = ""});
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; }
}
用法:同上
需求3.3:
model:
public class User1
{
public List<Test> Test { get; set; }
} public class User2
{
public Test2[] Test { get; set; }
}
用法:同上
需求3.4:
public class User1
{
public Test2[] Test { get; set; }
} public class User2
{
public List<Test> Test { get; set; }
}
同法:同上
总结:大致需求就是解决上述模型赋值问题,此方法由于赋值调用自身,可以实现无限下级模型赋值 如:User1.Test为复杂对象集合,Test类中也有复杂集合对象,无限让下执行
对与复杂集合内不同属性赋值也通过Dictionary传入, 如:User1.Test中Test.Name 赋值到Test2.Uname
我不晓得我表述清楚没有,反正大家慢慢看吧(我的错别字也是不太多,别介意→_→ )
原帖地址:http://www.cnblogs.com/jio92/p/CopyModel.html
反射 实现不同模型相同属性赋值 第二集(automapper)的更多相关文章
- Android利用反射机制为实体类属性赋值
在做android项目时,有时会遇到从网络上获取json类型数据,赋值给实体类,实体类属性少可以一个一个的赋值,如果实体类有很多属性,赋值可能就要耗很长的功夫了,幸好Java给我们提供了反射机制.下面 ...
- 31 反射方式给类的属性赋值 和 对象赋值(clone)
1.配置类 package com.da.tool.util.configuration.reflect; /** */ public class JobInfo { private String j ...
- Spring IoC 属性赋值阶段
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 容 ...
- Java循环一个对象的所有属性,并通过反射给这些属性赋值/取值
Java循环一个对象的所有属性,并通过反射给这些属性赋值/取值 说到循环遍历,最常见的遍历数组/列表.Map等.但是,在开发过程中,有时需要循环遍历一个对象的所有属性.遍历对象的属性该如何遍历呢?查了 ...
- 用反射的形式将一个对象属性值赋值给另一个对象,省略点get/set方法的冗余代码
1.本例使用的是idea 首先需要在idea中安装lombok插件,省略getter和setter方法的书写 在maven项目中加入lombok依赖 <dependency> <gr ...
- xml 转换成对象(采用反射机制对对对象属性赋值)
/// <summary> /// 采用反射机制对对对象属性赋值 /// </summary> /// <param name="node">& ...
- 【Java EE 学习 69 上】【struts2】【paramsPrepareParamsStack拦截器栈解决model对象和属性赋值冲突问题】
昨天有同学问我问题,他告诉我他的Action中的一个属性明明提供了get/set方法,但是在方法中却获取不到表单中传递过来的值.代码如下(简化后的代码) public class UserAction ...
- 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)
反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性.字段),而不去使用Invoke方法) 创建Delegate (1).Delegate.CreateDelegate(Type, ...
- Spring笔记04(DI(给属性赋值),自动装配(autowire))
给不同数据类型注入值: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="h ...
随机推荐
- 【转载】MySQL启多个实例
很多朋友都想在一台服务器上运行多个MySQL Instance,究竟怎么做呢?首先要明晰几个原理, 简称为mysqld读取my.cnf的顺序:第一搜,首先读取/etc/my.cnf,多实例这个配置文件 ...
- fopen()、 file_get_contents() 通过url获取链接内容
功能:获得网页内容 区别如下: fopen()打开URL 下面是一个使用fopen()打开URL的例子: <?php $fh = fopen('http://www.baidu.com/', ' ...
- Stanford coursera Andrew Ng 机器学习课程编程作业(Exercise 2)及总结
Exercise 1:Linear Regression---实现一个线性回归 关于如何实现一个线性回归,请参考:http://www.cnblogs.com/hapjin/p/6079012.htm ...
- MaskedTextBox的聚焦和光标位置
遇到一个关于MaskedTextBox聚焦和光标居左的问题. ①. 先说说聚焦: 起初给MaskedTextBox设置了Focus(),运行之后,并没有作用. 然后又给Form添加了Load事件,又设 ...
- YUV420查表法高效、无失真的转换为RGB32格式
YUV格式有两大类:planar和packed.planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V,这里所讲述的就是这中存储格式的:packed的YUV ...
- my_mosaic
//功能:输入想要打马赛克的坐标点,宽,高以及每个边需要划分的块数进行打马赛克 //只能处理位图,根据不同色深定义depth即可 //还没写从文件头读取图片分辨率 #include<unistd ...
- Linux 多线程编程
概念 原来指向main()的线程叫做主线程(main thread) 使用pthread_create()创建出来的线程,叫做子线程(child thread) 主/子线程只有在创建时才有区别, 创建 ...
- vim linux SecureCRT vim颜色的设置
解决方法: 1.首先按照环境一的方法检查一下,如果环境一的情况不在进行第二步. 2.修改终端TERM这个环境变量: 1)export命令 临时生效 # echo $TERM xterm #如果结果 ...
- Flex 布局教程:语法篇[转]
网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂直居中 ...
- 设计模式——抽象工厂模式及java实现
设计模式--抽象工厂模式及java实现 设计模式在大型软件工程中很重要,软件工程中采用了优秀的设计模式有利于代码维护,方便日后更改和添加功能. 设计模式有很多,而且也随着时间在不断增多,其中最著名的是 ...