之前使用的是网上的一个表达式树版本,使用时需要显示写出参数及返回值的类型 Tin TOut, 略显麻烦
public static class TransExpV2<TIn, TOut> { private static readonly Func<TIn, TOut> Func = GetFunc(); private static Func<TIn, TOut> GetFunc() { Type inType = typeof(TIn); Type outType = typeof(TOut); ParameterExpression parameterExpression = Expression.Parameter(inType, "inParam"); List<MemberBinding> memberBindingList = new List<MemberBinding>(); PropertyInfo[] inProperties = inType.GetProperties(); PropertyInfo[] outProperties = outType.GetProperties(); foreach (var inProp in inProperties) { foreach (var outProp in outProperties) { if (inProp.Name == outProp.Name) { if (outProp.CanWrite) { MemberExpression property = Expression.Property(parameterExpression, inProp); MemberBinding memberBinding = Expression.Bind(outProp, property); memberBindingList.Add(memberBinding); } break; } } } MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(outType), memberBindingList.ToArray()); Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression }); return lambda.Compile(); } public static TOut Trans(TIn tIn) { return Func(tIn); } }
经过一点研究,决定还是使用另外一种使用缓存的版本,只用指定返回类型即可。效率比上面的代码略低,但比普通的反射还是要快不少。
静态类中声明以下方法及即可
static Dictionary<string, object> dicMappedFunc = new Dictionary<string, object>(); public static T ToMapped<T>(this object instance) { if (instance == null) throw new ArgumentNullException(); Type instanceType = instance.GetType(); Type toType = typeof(T); string key = $"{instanceType.FullName}-{toType.FullName}"; if (!dicMappedFunc.ContainsKey(key)) { ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "instance"); List<MemberBinding> memberBindingList = new List<MemberBinding>(); PropertyInfo[] instanceProps = instanceType.GetCacheProperties(); PropertyInfo[] toProps = toType.GetCacheProperties(); foreach (PropertyInfo insProp in instanceProps) { foreach (PropertyInfo toProp in toProps) { if (insProp.Name == toProp.Name) { if (toProp.CanWrite) { MemberExpression property = Expression.Property(Expression.Convert(parameterExpression, instanceType), insProp); MemberBinding memberBinding = Expression.Bind(toProp, property); memberBindingList.Add(memberBinding); } break; } } } MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(toType), memberBindingList.ToArray()); Expression<Func<object, T>> lambda = Expression.Lambda<Func<object, T>>(memberInitExpression, new ParameterExpression[] { parameterExpression }); Func<object, T> func = lambda.Compile(); dicMappedFunc[key] = func; } var function = (Func<object, T>)dicMappedFunc[key]; return function(instance); }
使用时复制相同属性名的属性值,数据类型需相同