Ejemplo n.º 1
0
        /// <summary>
        /// 将对象克隆为指定类型的实例。
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        private static object InternalMapTo(this object source, object target, ConvertMapper mapper)
        {
            var sourceType = source.GetType();
            var targetType = target.GetType();

            //接口或抽象类,生成一个实现类
            if (targetType.IsInterface || targetType.IsAbstract)
            {
                targetType = targetType.BuildImplementType();
            }

            //如果可枚举
            if (source is IEnumerable enumerable && typeof(IEnumerable).IsAssignableFrom(targetType))
            {
                if (typeof(IDictionary).IsAssignableFrom(targetType))
                {
                    return(ConvertToDictionary(enumerable, targetType));
                }
                else
                {
                    return(ConvertToEnumerable(enumerable, targetType));
                }
            }

            var func = _cache.GetOrAdd($"{sourceType.FullName}-{targetType.FullName}-mapto", k =>
            {
                return(BuildMapToDelegate(source, target, targetType, mapper));
            });

            func.DynamicInvoke(source, target);
            return(target);
        }
Ejemplo n.º 2
0
        public void TestMapTo()
        {
            var mapper = new ConvertMapper <Data1, Data2>()
                         .Map(s => s.Description, s => s.Name + " test")
                         .Map(s => s.Other, s => "other");

            var data1 = new Data1 {
                Name = "fireasy"
            };
            var data2 = data1.To(mapper);

            Assert.AreEqual("fireasy test", data2.Description);
            Assert.AreEqual("other", data2.Other);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// 将对象克隆为指定类型的实例。
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="conversionType"></param>
        /// <returns></returns>
        private static object CloneTo(this object obj, Type conversionType, ConvertMapper mapper)
        {
            Guard.ArgumentNull(obj, nameof(obj));
            var sourceType = obj.GetType();

            if (conversionType.IsAssignableFrom(sourceType))
            {
                return(obj);
            }

            //接口或抽象类,生成一个实现类
            if (conversionType.IsInterface || conversionType.IsAbstract)
            {
                conversionType = conversionType.BuildImplementType();
            }

            //如果可枚举
            var enumerable = obj as IEnumerable;

            if (enumerable != null && typeof(IEnumerable).IsAssignableFrom(conversionType))
            {
                if (typeof(IDictionary).IsAssignableFrom(conversionType))
                {
                    return(ConvertToDictionary(enumerable, conversionType));
                }
                else
                {
                    return(ConvertToEnumerable(enumerable, conversionType));
                }
            }

            var cacheMgr = MemoryCacheManager.Instance;
            var func     = cacheMgr.TryGet(sourceType.FullName + "-" + conversionType.FullName, () => BuildCloneToDelegate(obj, conversionType, mapper));

            return(func.DynamicInvoke(obj));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// 将对象克隆为指定类型的实例。
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="conversionType"></param>
        /// <returns></returns>
        private static object CloneTo(this object obj, Type conversionType, ConvertMapper mapper)
        {
            Guard.ArgumentNull(obj, nameof(obj));
            var sourceType = obj.GetType();

            if (conversionType.IsAssignableFrom(sourceType))
            {
                return(obj);
            }

            //接口或抽象类,生成一个实现类
            if (conversionType.IsInterface || conversionType.IsAbstract)
            {
                conversionType = conversionType.BuildImplementType();
            }

            //如果可枚举
            if (obj is IEnumerable enumerable && typeof(IEnumerable).IsAssignableFrom(conversionType))
            {
                if (typeof(IDictionary).IsAssignableFrom(conversionType))
                {
                    return(ConvertToDictionary(enumerable, conversionType));
                }
                else
                {
                    return(ConvertToEnumerable(enumerable, conversionType));
                }
            }

            var func = _cache.GetOrAdd($"{sourceType.FullName}-{conversionType.FullName}", k =>
            {
                return(BuildCloneToDelegate(obj, conversionType, mapper));
            });

            return(func.DynamicInvoke(obj));
        }
Ejemplo n.º 5
0
        private static void GetGeneralMemberBindings(object obj, Type sourceType, Type conversionType, ParameterExpression parExp, List <MemberBinding> bindings, ConvertMapper mapper)
        {
            var lazyMgr = obj as ILazyManager;

            foreach (var property in conversionType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                try
                {
                    if (lazyMgr != null && !lazyMgr.IsValueCreated(property.Name))
                    {
                        continue;
                    }

                    Expression descExp = null;

                    //在映射器里查找转换表达式
                    if (mapper != null)
                    {
                        descExp = mapper.GetMapExpression(property);
                        if (descExp != null)
                        {
                            descExp = (ExpressionReplacer.Replace(descExp, parExp) as LambdaExpression).Body;
                        }
                    }

                    if (descExp == null)
                    {
                        var sourceProperty = sourceType.GetProperty(property.Name, BindingFlags.Public | BindingFlags.Instance);
                        if (sourceProperty == null || !sourceProperty.CanRead || !property.CanWrite)
                        {
                            continue;
                        }

                        descExp = Expression.MakeMemberAccess(parExp, sourceProperty);
                        if (property.PropertyType != sourceProperty.PropertyType)
                        {
                            descExp = Expression.Call(null, MthToType,
                                                      Expression.Convert(descExp, typeof(object)),
                                                      Expression.Constant(property.PropertyType),
                                                      Expression.Constant(null));
                            descExp = Expression.Convert(descExp, property.PropertyType);
                        }
                    }

                    bindings.Add(Expression.Bind(property, descExp));
                }
                catch
                {
                    continue;
                }
            }
        }
Ejemplo n.º 6
0
        private static void GetDynamicMemberBindings(IDynamicMetaObjectProvider @dynamic, Type conversionType, ParameterExpression parExp, List <MemberBinding> bindings, ConvertMapper mapper)
        {
            var method     = typeof(DynamicManager).GetMethod("GetMember", BindingFlags.Instance | BindingFlags.Public);
            var metaObject = @dynamic.GetMetaObject(Expression.Constant(@dynamic));
            var metaObjExp = Expression.TypeAs(parExp, typeof(IDynamicMetaObjectProvider));

            foreach (var name in metaObject.GetDynamicMemberNames())
            {
                try
                {
                    var descProperty = conversionType.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
                    if (descProperty == null || !descProperty.CanWrite)
                    {
                        continue;
                    }

                    var mgrExp = Expression.New(typeof(DynamicManager));
                    var exp    = (Expression)Expression.Call(mgrExp, method, metaObjExp, Expression.Constant(name));
                    exp = Expression.Call(null, MthToType, exp, Expression.Constant(descProperty.PropertyType), Expression.Constant(null));
                    exp = (Expression)Expression.Convert(exp, descProperty.PropertyType);
                    bindings.Add(Expression.Bind(descProperty, exp));
                }
                catch
                {
                    continue;
                }
            }
        }
Ejemplo n.º 7
0
        private static Delegate BuildCloneToDelegate(object obj, Type conversionType, ConvertMapper mapper)
        {
            var sourceType = obj.GetType();
            var bindings   = new List <MemberBinding>();
            var parExp     = Expression.Parameter(sourceType, "s");

#if !NET35
            TypeDescriptorUtility.AddDefaultDynamicProvider();
            var @dynamic = obj as IDynamicMetaObjectProvider;
            if (@dynamic != null)
            {
                GetDynamicMemberBindings(@dynamic, conversionType, parExp, bindings, mapper);
            }
            else
            {
                GetGeneralMemberBindings(obj, sourceType, conversionType, parExp, bindings, mapper);
            }
#else
            GetGeneralMemberBindings(obj, sourceType, conversionType, parExp, bindings, mapper);
#endif

            var expExp     = Expression.New(conversionType);
            var mbrInitExp = Expression.MemberInit(expExp, bindings);
            var funcType   = typeof(Func <,>).MakeGenericType(sourceType, conversionType);
            var lambda     = Expression.Lambda(funcType, mbrInitExp, parExp);
            return(lambda.Compile());
        }
Ejemplo n.º 8
0
        /// <summary>
        /// 将对象转换为指定的类型。
        /// </summary>
        /// <param name="value">源对象。</param>
        /// <param name="conversionType">要转换的对象类型。</param>
        /// <param name="defaultValue">转换失败后返回的默认值。</param>
        /// <param name="mapper">转换器。</param>
        /// <returns></returns>
        public static object ToType(this object value, Type conversionType, object defaultValue = null, ConvertMapper mapper = null)
        {
            Guard.ArgumentNull(conversionType, nameof(conversionType));
            if (value.IsNullOrEmpty())
            {
                return(conversionType.IsNullableType() ? null : (defaultValue ?? conversionType.GetDefaultValue()));
            }
            if (value.GetType() == conversionType)
            {
                return(value);
            }

            try
            {
                if (conversionType.IsEnum)
                {
                    return(Enum.Parse(conversionType, value.ToString(), true));
                }
                if (conversionType == typeof(bool?) && Convert.ToInt32(value) == -1)
                {
                    return(null);
                }

                if (conversionType.IsNullableType())
                {
                    return(conversionType.New(new[] { value.ToType(conversionType.GetGenericArguments()[0]) }));
                }
                if (conversionType == typeof(bool))
                {
                    if (value is string)
                    {
                        var lower = ((string)value).ToLower();
                        return(lower == "true" || lower == "t" || lower == "1" || lower == "yes" || lower == "on");
                    }
                    return(Convert.ToInt32(value) == 1);
                }
                if (value is bool)
                {
                    if (conversionType == typeof(string))
                    {
                        return(Convert.ToBoolean(value) ? "true" : "false");
                    }
                    return(Convert.ToBoolean(value) ? 1 : 0);
                }
                if (conversionType == typeof(Type))
                {
                    return(Type.GetType(value.ToString(), false, true));
                }
                if (value is Type && conversionType == typeof(string))
                {
                    return(((Type)value).FullName);
                }
                if (typeof(IConvertible).IsAssignableFrom(conversionType))
                {
                    return(Convert.ChangeType(value, conversionType, null));
                }

                return(value.CloneTo(conversionType, mapper));
            }
            catch (Exception exp)
            {
                return(defaultValue);
            }
        }
Ejemplo n.º 9
0
 /// <summary>
 /// 将对象转换为指定的类型。
 /// </summary>
 /// <typeparam name="TSource">对象的类型。</typeparam>
 /// <typeparam name="TTarget">要转换的类型。</typeparam>
 /// <param name="source">源对象。</param>
 /// <param name="mapper">转换器。</param>
 /// <returns></returns>
 public static TTarget To <TSource, TTarget>(this TSource source, ConvertMapper <TSource, TTarget> mapper)
 {
     return((TTarget)ToType(source, typeof(TTarget), default(TTarget), mapper));
 }
Ejemplo n.º 10
0
        private static void GetGeneralMemberAssignments(object source, object target,
                                                        Type sourceType, Type targetType, ParameterExpression sourceParExp, ParameterExpression targetParExp,
                                                        List <BinaryExpression> assignments, ConvertMapper mapper)
        {
            foreach (var property in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                try
                {
                    if (source is ILazyManager lazyMgr && !lazyMgr.IsValueCreated(property.Name))
                    {
                        continue;
                    }

                    Expression sourceExp = null;

                    //在映射器里查找转换表达式
                    if (mapper != null)
                    {
                        sourceExp = mapper.GetMapExpression(property);
                        if (sourceExp != null)
                        {
                            sourceExp = (ExpressionReplacer.Replace(sourceExp, sourceParExp) as LambdaExpression).Body;
                        }
                    }

                    if (sourceExp == null)
                    {
                        var sourceProperty = sourceType.GetProperty(property.Name, BindingFlags.Public | BindingFlags.Instance);
                        if (sourceProperty == null || !sourceProperty.CanRead || !property.CanWrite)
                        {
                            continue;
                        }

                        sourceExp = GetPropertyExpression(sourceParExp, target, property, sourceProperty);
                    }

                    var descExp = Expression.MakeMemberAccess(targetParExp, property);
                    assignments.Add(Expression.Assign(descExp, sourceExp));
                }
                catch
                {
                    continue;
                }
            }
        }
Ejemplo n.º 11
0
        private static void GetDynamicMemberAssignments(IDynamicMetaObjectProvider @dynamic, Type targetType,
                                                        ParameterExpression sourceParExp, ParameterExpression targetParExp, List <BinaryExpression> assignments, ConvertMapper mapper)
        {
            var method     = typeof(DynamicManager).GetMethod(nameof(DynamicManager.GetMember), BindingFlags.Instance | BindingFlags.Public);
            var metaObject = @dynamic.GetMetaObject(Expression.Constant(@dynamic));
            var metaObjExp = Expression.TypeAs(sourceParExp, typeof(IDynamicMetaObjectProvider));

            foreach (var name in metaObject.GetDynamicMemberNames())
            {
                try
                {
                    var descProperty = targetType.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
                    if (descProperty == null || !descProperty.CanWrite)
                    {
                        continue;
                    }

                    var mgrExp = Expression.New(typeof(DynamicManager));
                    var exp    = (Expression)Expression.Call(mgrExp, method, metaObjExp, Expression.Constant(name));
                    exp = Expression.Call(null, MethodCache.ToType, exp, Expression.Constant(descProperty.PropertyType), Expression.Constant(null), Expression.Constant(null, typeof(ConvertMapper)));
                    exp = (Expression)Expression.Convert(exp, descProperty.PropertyType);
                    var descExp = Expression.MakeMemberAccess(targetParExp, descProperty);
                    assignments.Add(Expression.Assign(descExp, exp));
                }
                catch
                {
                    continue;
                }
            }
        }
Ejemplo n.º 12
0
        private static Delegate BuildMapToDelegate(object source, object target, Type conversionType, ConvertMapper mapper)
        {
            var sourceType   = source.GetType();
            var assignments  = new List <BinaryExpression>();
            var sourceParExp = Expression.Parameter(sourceType, "s");
            var targetParExp = Expression.Parameter(conversionType, "t");

            TypeDescriptorUtility.AddDefaultDynamicProvider();
            if (source is IDynamicMetaObjectProvider @dynamic)
            {
                GetDynamicMemberAssignments(@dynamic, conversionType, sourceParExp, targetParExp, assignments, mapper);
            }
            else
            {
                GetGeneralMemberAssignments(source, target, sourceType, conversionType, sourceParExp, targetParExp, assignments, mapper);
            }

            var blockExp = Expression.Block(assignments);
            var funcType = typeof(Action <,>).MakeGenericType(sourceType, conversionType);
            var lambda   = Expression.Lambda(funcType, blockExp, sourceParExp, targetParExp);

            return(lambda.Compile());
        }
Ejemplo n.º 13
0
        /// <summary>
        /// 将源对象映射到目标对象。
        /// </summary>
        /// <typeparam name="TSource">对象的类型。</typeparam>
        /// <typeparam name="TTarget">要转换的类型。</typeparam>
        /// <param name="source">源对象。</param>
        /// <param name="target">目标对象。</param>
        /// <param name="mapper">转换器。</param>
        /// <returns></returns>
        public static TTarget MapTo <TSource, TTarget>(this TSource source, TTarget target, ConvertMapper mapper = null)
        {
            Guard.ArgumentNull(source, nameof(source));
            Guard.ArgumentNull(target, nameof(target));

            return((TTarget)InternalMapTo(source, target, mapper));
        }