//缓存表达式树
private static Dictionary<string, object> objCache = new Dictionary<string, object>();
/// <summary>
/// 使用表达式树为两个对象的相同属性赋值
/// </summary>
/// <typeparam name="TIn">源对象</typeparam>
/// <typeparam name="TOut">目标对象</typeparam>
/// <param name="tIn">源实例</param>
/// <returns>目标实例</returns>
private static TOut ObjCopyByExpressionTree<TIn, TOut>(TIn tIn)
{
string key = string.Format("Key_{0}_To_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
if (!objCache.ContainsKey(key))
{
//表示一个命名的参数表达式
//创建一个 System.Linq.Expressions.ParameterExpression 节点,该节点可用于标识表达式树中的参数或变量
// type:
// 参数或变量的类型。
//
// name:
// 仅用于调试或打印目的的参数或变量的名称
ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "parameter");
//提供表示绑定的类派生自的基类,这些绑定用于对新创建对象的成员进行初始化
List<MemberBinding> memberBindingList = new List<MemberBinding>();
foreach (var item in typeof(TOut).GetProperties())
{
//表示访问字段或属性
// expression:
// 要将 System.Linq.Expressions.Expression 属性设置为与其相等的 System.Linq.Expressions.MemberExpression.Expression。
// 对于静态属性,这可以为 null。
//
// property:
// 要将 System.Reflection.PropertyInfo 属性设置为与其相等的 System.Linq.Expressions.MemberExpression.Member。
MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
//提供表示绑定的类派生自的基类,这些绑定用于对新创建对象的成员进行初始化。
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingList.Add(memberBinding);
};
//表示调用构造函数并初始化新对象的一个或多个成员。
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
//将强类型化的 Lambda 表达式表示为表达式树形式的数据结构
Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
//封装一个方法,该方法具有一个参数,且返回由 TResult 参数指定的类型的值
//编译表达式树由描述为可执行代码的 lambda 表达式,并生成一个委托,表示 lambda 表达式
Func<TIn, TOut> func = lambda.Compile();
objCache[key] = func;
}
return ((Func<TIn, TOut>)objCache[key])(tIn);
}
private static void ExpTrans(ILoginUser loginUser, ref IVoState voState, Dictionary<string, string> mappingDic = null)
{
List<MemberBinding> memberBindingList = new List<MemberBinding>();
ParameterExpression parameterExpression = Expression.Parameter(typeof(ILoginUser), "p");
//目标
var targetAllPropertys = voState.GetType().GetProperties();
var targetparamNames = mappingDic ?? new Dictionary<string, string>(targetAllPropertys.Select(t => new KeyValuePair<string, string>(t.Name, t.Name)));
foreach (var item in targetparamNames)
{
var itemProperty = targetAllPropertys.FirstOrDefault(t => t.Name == item.Key && t.CanWrite);
if (itemProperty == null)
continue;
if (string.IsNullOrEmpty(item.Value) || loginUser.GetType().GetProperty(item.Value) == null)
{
//来源不存在该对应的属性
if (itemProperty.PropertyType == typeof(string))
memberBindingList.Add(Expression.Bind(itemProperty, Expression.Constant(string.Empty)));
if (itemProperty.PropertyType == typeof(DateTime))
memberBindingList.Add(Expression.Bind(itemProperty, Expression.Constant(DateTime.Now, typeof(DateTime))));
if (itemProperty.PropertyType == typeof(Nullable<DateTime>))
memberBindingList.Add(Expression.Bind(itemProperty, Expression.Constant(DateTime.Now, typeof(Nullable<DateTime>))));
continue;
}
memberBindingList.Add(Expression.Bind(itemProperty, Expression.Property(parameterExpression, item.Value)));
}
if (memberBindingList.Any() == false)
return;
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(voState.GetType()), memberBindingList.ToArray());
Expression<Func<ILoginUser, IVoState>> lambda = Expression.Lambda<Func<ILoginUser, IVoState>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
voState = lambda.Compile().Invoke(loginUser);
}
private static TTarget ExpTrans<TSource, TTarget>(TSource message, Func<string, string> mappingPropery = null, Func<PropertyInfo, ConstantExpression> bindConstantExpressionWhenNull = null) where TTarget : class, new()
{
mappingPropery ??= (t) => t;
bindConstantExpressionWhenNull ??= (t) =>
{
if (t.PropertyType == typeof(string))
return Expression.Constant(string.Empty);
if (t.PropertyType == typeof(DateTime))
return Expression.Constant(DateTime.Now, typeof(DateTime));
if (t.PropertyType == typeof(Nullable<DateTime>))
return Expression.Constant(DateTime.Now, typeof(Nullable<DateTime>));
return null;
};
var target = Expression.Parameter(typeof(TTarget));
var source = Expression.Parameter(message.GetType());
var sourceProps = message.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.CanRead).ToList();
var targetPros = typeof(TTarget).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.CanWrite).ToList();
List<Expression> blocks = new(targetPros.Count);
foreach (var mappPros in targetPros)
{
var sourceName = mappingPropery.Invoke(mappPros.Name);
if (sourceProps.Any(t => t.Name == sourceName))
{
blocks.Add(Expression.Assign(Expression.Property(target, mappPros), Expression.Property(source, sourceName)));
continue;
}
Expression constExpression = bindConstantExpressionWhenNull.Invoke(mappPros);
if (constExpression == null)
continue;
blocks.Add(Expression.Assign(Expression.Property(target, mappPros), constExpression));
}
var block = Expression.Block(blocks);
var setter = Expression.Lambda<Action<TTarget, TSource>>(block, target, source).Compile();
TTarget target1 = new();
setter.Invoke(target1, message);
return target1;
}