实现和上个用DynamicMethod的方式生成的复制实体类对应一样功能
代码
public static class ExpMapper<TTarget,TSource>
{
private static MapMethod<TTarget, TSource> mapMethod;
public static MapMethod<TTarget, TSource> GetMapMethod()
{
if (mapMethod == null)
{
mapMethod = CreateMapMethod(typeof(TTarget), typeof(TSource));
}
return mapMethod;
}
public static TTarget Map(TSource source)
{
if (mapMethod == null)
{
mapMethod = CreateMapMethod(typeof(TTarget), typeof(TSource));
}
return mapMethod(source);
}
private static MapMethod<TTarget, TSource> CreateMapMethod(Type targetType, Type sourceType)
{
var source = Expression.Parameter(sourceType, "source");
var binds = (from sp in sourceType.GetProperties()
from tp in targetType.GetProperties()
where sp.Name == tp.Name
select Expression.Bind(tp, Expression.Property(source, sp))).ToArray();
Expression body = Expression.MemberInit(Expression.New(typeof(TTarget)), binds);
return Expression.Lambda<MapMethod<TTarget, TSource>>(body,source).Compile();
}
}
{
private static MapMethod<TTarget, TSource> mapMethod;
public static MapMethod<TTarget, TSource> GetMapMethod()
{
if (mapMethod == null)
{
mapMethod = CreateMapMethod(typeof(TTarget), typeof(TSource));
}
return mapMethod;
}
public static TTarget Map(TSource source)
{
if (mapMethod == null)
{
mapMethod = CreateMapMethod(typeof(TTarget), typeof(TSource));
}
return mapMethod(source);
}
private static MapMethod<TTarget, TSource> CreateMapMethod(Type targetType, Type sourceType)
{
var source = Expression.Parameter(sourceType, "source");
var binds = (from sp in sourceType.GetProperties()
from tp in targetType.GetProperties()
where sp.Name == tp.Name
select Expression.Bind(tp, Expression.Property(source, sp))).ToArray();
Expression body = Expression.MemberInit(Expression.New(typeof(TTarget)), binds);
return Expression.Lambda<MapMethod<TTarget, TSource>>(body,source).Compile();
}
}
.net 4中添加了不少新的Expression。比如Expression.Assign用来赋值,Expression.Variable定义变量,等等用来生成代码会更加的直观。effective c# 第二版上有个例子
代码如下
代码
var source = Expression.Parameter(typeof(TSource),"source");
var dest = Expression.Variable(typeof(TDest), "dest");
var assignments = from srcProp in typeof(TSource).GetProperties(BindingFlags.Public |BindingFlags.Instance)
where srcProp.CanRead
let destProp = typeof(TDest).GetProperty(srcProp.Name,BindingFlags.Public |BindingFlags.Instance)
where (destProp != null) &&
(destProp.CanWrite)
select Expression.Assign(Expression.Property(dest,destProp),Expression.Property(source,srcProp));
// put together the body:
var body = new List<Expression>();
body.Add(Expression.Assign(dest,Expression.New(typeof(TDest))));
body.AddRange(assignments);
body.Add(dest);
var expr =
Expression.Lambda<Func<TSource, TDest>>(
Expression.Block(
new[] { dest }, // expression parameters
body.ToArray() // body
),
source // lambda expression
);
var func = expr.Compile();
var dest = Expression.Variable(typeof(TDest), "dest");
var assignments = from srcProp in typeof(TSource).GetProperties(BindingFlags.Public |BindingFlags.Instance)
where srcProp.CanRead
let destProp = typeof(TDest).GetProperty(srcProp.Name,BindingFlags.Public |BindingFlags.Instance)
where (destProp != null) &&
(destProp.CanWrite)
select Expression.Assign(Expression.Property(dest,destProp),Expression.Property(source,srcProp));
// put together the body:
var body = new List<Expression>();
body.Add(Expression.Assign(dest,Expression.New(typeof(TDest))));
body.AddRange(assignments);
body.Add(dest);
var expr =
Expression.Lambda<Func<TSource, TDest>>(
Expression.Block(
new[] { dest }, // expression parameters
body.ToArray() // body
),
source // lambda expression
);
var func = expr.Compile();