/// <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); }
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); }
/// <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)); }
/// <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)); }
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; } } }
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; } } }
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()); }
/// <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); } }
/// <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)); }
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; } } }
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; } } }
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()); }
/// <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)); }