使用反射+缓存+委托,实现一个不同对象之间同名同类型属性值的快速拷贝
最近实践一个DDD项目,在领域层与持久层之间,Domain Model与Entity Model之间有时候需要进行属性值得拷贝,而这些属性,尽管它所在的类名称不一样,但它们的属性名和属性类型差不多都是一样的。系统中有不少这样的Model需要相互转换,有朋友推荐使用AutoMapper,试了下果然不错,解决了问题,但作为一个老鸟,决定研究下实现原理,于是动手也来山寨一个。为了让这个“轮子”尽量有实用价值,效率肯定是需要考虑的,所以决定采用“反射+缓存+委托”的路子。
第一次使用,肯定要反射出来对象的属性,这个简单,就下面的代码:
Type targetType;
//....
PropertyInfo[] targetProperties = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
这里只获取公开的实例对象的属性。
要实现同名同类型的属性拷贝,那么需要把这些属性找出来,下面是完整的代码:
public ModuleCast(Type sourceType, Type targetType)
{
PropertyInfo[] targetProperties = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo sp in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
foreach (PropertyInfo tp in targetProperties)
{
if (sp.Name == tp.Name && sp.PropertyType == tp.PropertyType)
{
CastProperty cp = new CastProperty();
cp.SourceProperty = new PropertyAccessorHandler(sp);
cp.TargetProperty = new PropertyAccessorHandler(tp);
mProperties.Add(cp);
break;
}
}
}
}
这里使用了一个 CastProperty 类来保存要处理的源对象和目标对象,并且把这组对象放到一个CastProperty 列表的mProperties 静态对象里面缓存起来。
下面是 CastProperty 类的定义:
/// <summary>
/// 转换属性对象
/// </summary>
public class CastProperty
{
public PropertyAccessorHandler SourceProperty
{
get;
set;
}
public PropertyAccessorHandler TargetProperty
{
get;
set;
}
}
类本身很简单,关键就是这个属性访问器PropertyAccessorHandler 对象,下面是它的定义:
/// <summary>
/// 属性访问器
/// </summary>
public class PropertyAccessorHandler
{
public PropertyAccessorHandler(PropertyInfo propInfo)
{
this.PropertyName = propInfo.Name;
//var obj = Activator.CreateInstance(classType);
//var getterType = typeof(FastPropertyAccessor.GetPropertyValue<>).MakeGenericType(propInfo.PropertyType);
//var setterType = typeof(FastPropertyAccessor.SetPropertyValue<>).MakeGenericType(propInfo.PropertyType);
//this.Getter = Delegate.CreateDelegate(getterType, null, propInfo.GetGetMethod());
//this.Setter = Delegate.CreateDelegate(setterType, null, propInfo.GetSetMethod());
if (propInfo.CanRead)
this.Getter = propInfo.GetValue;
if (propInfo.CanWrite)
this.Setter = propInfo.SetValue;
}
public string PropertyName { get; set; }
public Func<object, object[], object> Getter { get; private set; }
public Action<object, object, object[]> Setter { get; private set; }
}
在写这个类的时候,曾经走了好几次弯路,前期准备通过 Delegate.CreateDelegate 方式创建一个当前属性Get和Set方法的委托,但是经过数次测试发现,
Delegate.CreateDelegate(getterType, obj, propInfo.GetGetMethod());
这里的obj 要么是一个对象实例,要么是null,如果是null,那么这个委托定义只能绑定到类型的静态属性方法上;如果不是null,那么这个委托只能绑定到当前 obj 实例对象上,换句话说,如果将来用obj类型的另外一个实例对象,那么这个委托访问的还是之前那个obj 对象,跟新对象实例无关。
PS:为了走这条“弯路”,前几天还特意写了一个FastPropertyAccessor,申明了2个泛型委托,来绑定属性的Get和Set方法,即上面注释掉的2行代码:
var getterType = typeof(FastPropertyAccessor.GetPropertyValue<>).MakeGenericType(propInfo.PropertyType);
var setterType = typeof(FastPropertyAccessor.SetPropertyValue<>).MakeGenericType(propInfo.PropertyType);
好不容易将这个泛型委托创建出来了,编译也通过了,却发现最终没法使用,别提有多郁闷了:-《
回归话题,有了PropertyAccessorHandler,那么我们只需要遍历当前要转换的目标类型的属性集合,就可以开始对属性进行拷贝了:
public void Cast(object source, object target)
{
if (source == null)
throw new ArgumentNullException("source");
if (target == null)
 
补充:Web开发 , ASP.Net ,
- 更多asp疑问解答:
- asp正则过滤重复字符串的代码
- 用asp过滤全部html但保留br类似的符号
- 会asp,但感觉asp要过点,想学php。但我一般做的都是小公司的站,用access数
- PHP的空间可以用ASP的源代码吗?
- 以前做asp程序,现在应该怎样发展?是学.net还是php
- 以前做asp程序,现在应该怎样发展?是学.net还是php
- 想做一个市级的人才网acess,sql数据库,语言asp,jsp,php分别用哪种好
- jsp,asp,php 区别
- 我想找一个有比较多漏洞的网站的源码,比如可以asp,php注入等都可以。供学习研究用。请提供下载地址。。
- 现在候找人做个网站,用ASP,还是PHP语言去做好
- asp,php ,jsp,.net 对于做网站前台的重要吗?
- asp和php的区别是什么?
- 我是新手SEO菜鸟 请问wp dw php asp cms myspl dede 这些软件应该如何区分呀?
- 网页制作相关的三种语言:ASP JSP PHP那个好点,简单点?
- 网页制作相关的三种语言:ASP JSP PHP那个好点,简单点?