C# 使用表达式树复制属性值,转化为指定类型 ExpressionTree CopyProperties

之前使用的是网上的一个表达式树版本,使用时需要显示写出参数及返回值的类型 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);
        }

 

使用时复制相同属性名的属性值,数据类型需相同

posted @ 2019-06-01 22:41  逍遥子k  阅读(703)  评论(0编辑  收藏  举报