diff --git a/src/Mapster/Adapters/BaseAdapter.cs b/src/Mapster/Adapters/BaseAdapter.cs index 4a351ebc..f1033bd2 100644 --- a/src/Mapster/Adapters/BaseAdapter.cs +++ b/src/Mapster/Adapters/BaseAdapter.cs @@ -13,12 +13,12 @@ public abstract class BaseAdapter protected virtual int Score => 0; protected virtual bool CheckExplicitMapping => true; - public virtual int? Priority(Type sourceType, Type destinationType, MapType mapType) + public virtual int? Priority(PreCompileArgument arg) { - return CanMap(sourceType, destinationType, mapType) ? this.Score : (int?)null; + return CanMap(arg) ? this.Score : (int?)null; } - protected abstract bool CanMap(Type sourceType, Type destinationType, MapType mapType); + protected abstract bool CanMap(PreCompileArgument arg); public LambdaExpression CreateAdaptFunc(CompileArgument arg) { @@ -87,7 +87,7 @@ protected virtual Expression CreateExpressionBody(Expression source, Expression { if (this.CheckExplicitMapping && arg.Context.Config.RequireExplicitMapping - && !arg.Context.Config.RuleMap.ContainsKey(new TypeTuple(arg.SourceType, arg.DestinationType))) + && !arg.ExplicitMapping) { throw new InvalidOperationException("Implicit mapping is not allowed (check GlobalSettings.RequireExplicitMapping) and no configuration exists"); } diff --git a/src/Mapster/Adapters/BaseAfterMapper.cs b/src/Mapster/Adapters/BaseAfterMapper.cs index c724e729..3832cad4 100644 --- a/src/Mapster/Adapters/BaseAfterMapper.cs +++ b/src/Mapster/Adapters/BaseAfterMapper.cs @@ -7,12 +7,12 @@ public abstract class BaseAfterMapper { protected virtual int Score => 0; - public virtual int? Priority(Type sourceType, Type destinationType, MapType mapType) + public virtual int? Priority(PreCompileArgument arg) { - return CanMap(sourceType, destinationType, mapType) ? this.Score : (int?)null; + return CanMap(arg) ? this.Score : (int?)null; } - protected abstract bool CanMap(Type sourceType, Type destinationType, MapType mapType); + protected abstract bool CanMap(PreCompileArgument arg); public LambdaExpression CreateAfterMapFunc(CompileArgument arg) { diff --git a/src/Mapster/Adapters/ClassAdapter.cs b/src/Mapster/Adapters/ClassAdapter.cs index ef867f70..dacf69d7 100644 --- a/src/Mapster/Adapters/ClassAdapter.cs +++ b/src/Mapster/Adapters/ClassAdapter.cs @@ -18,12 +18,9 @@ internal class ClassAdapter : BaseClassAdapter { protected override int Score => -150; - protected override bool CanMap(Type sourceType, Type destinationType, MapType mapType) + protected override bool CanMap(PreCompileArgument arg) { - if (sourceType == typeof(string) || sourceType == typeof(object)) - return false; - - if (!destinationType.IsPoco()) + if (!arg.DestinationType.IsPoco()) return false; return true; diff --git a/src/Mapster/Adapters/CollectionAdapter.cs b/src/Mapster/Adapters/CollectionAdapter.cs index f22f88b0..e4d8efb0 100644 --- a/src/Mapster/Adapters/CollectionAdapter.cs +++ b/src/Mapster/Adapters/CollectionAdapter.cs @@ -13,11 +13,11 @@ internal class CollectionAdapter : BaseAdapter protected override int Score => -125; protected override bool CheckExplicitMapping => false; - protected override bool CanMap(Type sourceType, Type destinationType, MapType mapType) + protected override bool CanMap(PreCompileArgument arg) { - return sourceType.IsCollection() - && destinationType.IsCollection() - && destinationType.IsListCompatible(); + return arg.SourceType.IsCollection() + && arg.DestinationType.IsCollection() + && arg.DestinationType.IsListCompatible(); } private static Expression CreateCountExpression(Expression source, bool allowCountAll) diff --git a/src/Mapster/Adapters/DelegateAdapter.cs b/src/Mapster/Adapters/DelegateAdapter.cs index 8553f972..807825c2 100644 --- a/src/Mapster/Adapters/DelegateAdapter.cs +++ b/src/Mapster/Adapters/DelegateAdapter.cs @@ -12,7 +12,7 @@ public DelegateAdapter(LambdaExpression lambda) _lambda = lambda; } - protected override bool CanMap(Type sourceType, Type destinationType, MapType mapType) + protected override bool CanMap(PreCompileArgument arg) { throw new NotImplementedException(); } diff --git a/src/Mapster/Adapters/DictionaryAdapter.cs b/src/Mapster/Adapters/DictionaryAdapter.cs index add74d71..b0fe4de0 100644 --- a/src/Mapster/Adapters/DictionaryAdapter.cs +++ b/src/Mapster/Adapters/DictionaryAdapter.cs @@ -12,12 +12,9 @@ internal class DictionaryAdapter : ClassAdapter { protected override int Score => -124; - protected override bool CanMap(Type sourceType, Type destinationType, MapType mapType) + protected override bool CanMap(PreCompileArgument arg) { - if (sourceType == typeof (string) || sourceType == typeof (object)) - return false; - - var dictType = destinationType.GetDictionaryType(); + var dictType = arg.DestinationType.GetDictionaryType(); return dictType?.GetGenericArguments()[0] == typeof (string); } diff --git a/src/Mapster/Adapters/ObjectAdapter.cs b/src/Mapster/Adapters/ObjectAdapter.cs new file mode 100644 index 00000000..7720c13d --- /dev/null +++ b/src/Mapster/Adapters/ObjectAdapter.cs @@ -0,0 +1,40 @@ +using System; +using System.Linq.Expressions; + +namespace Mapster.Adapters +{ + internal class ObjectAdapter : BaseAdapter + { + protected override int Score => -111; + + protected override bool CanMap(PreCompileArgument arg) + { + return arg.SourceType == typeof(object) || arg.DestinationType == typeof(object); + } + + protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) + { + throw new NotImplementedException(); + } + + protected override Expression CreateInlineExpression(Expression source, CompileArgument arg) + { + // object, T + + //if (src.GetType() == typeof(object)) + // return (T)src + + //return src.Adapt(); + + // poco, object + + //return (object)src.Adapt(); + + // object, object + + //if (src.GetType() == typeof(object)) + // return src; + // return src.Adapt(src.GetType(), src.GetType()); + } + } +} diff --git a/src/Mapster/Adapters/PrimitiveAdapter.cs b/src/Mapster/Adapters/PrimitiveAdapter.cs index f1bab5f7..0acb6898 100644 --- a/src/Mapster/Adapters/PrimitiveAdapter.cs +++ b/src/Mapster/Adapters/PrimitiveAdapter.cs @@ -1,4 +1,6 @@ -using System; +using Mapster.Utils; +using System; +using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; @@ -9,7 +11,7 @@ internal class PrimitiveAdapter : BaseAdapter protected override int Score => -200; protected override bool CheckExplicitMapping => false; - protected override bool CanMap(Type sourceType, Type destinationType, MapType mapType) + protected override bool CanMap(PreCompileArgument arg) { return true; } @@ -25,7 +27,7 @@ protected override Expression CreateExpressionBody(Expression source, Expression { convert = Expression.Convert(convert, sourceType.GetGenericArguments()[0]); } - convert = ReflectionUtils.BuildUnderlyingTypeConvertExpression(convert, sourceType, destinationType, arg.Settings); + convert = ConvertType(convert, arg); if (convert.Type != destinationType) convert = Expression.Convert(convert, destinationType); @@ -41,6 +43,66 @@ protected override Expression CreateExpressionBody(Expression source, Expression return convert; } + protected virtual Expression ConvertType(Expression source, CompileArgument arg) + { + var srcType = arg.SourceType.UnwrapNullable(); + var destType = arg.DestinationType.UnwrapNullable(); + + if (srcType == destType) + return source; + + if (destType.GetTypeInfo().IsEnum && srcType.GetTypeInfo().IsEnum && arg.Settings.MapEnumByName == true) + { + var method = typeof(Enum<>).MakeGenericType(srcType).GetMethod("ToString", new[] { srcType }); + var tostring = Expression.Call(method, source); + var methodParse = typeof(Enum<>).MakeGenericType(destType).GetMethod("Parse", new[] { typeof(string) }); + + return Expression.Call(methodParse, tostring); + } + + if (IsObjectToPrimitiveConversion(srcType, destType)) + { + return CreateConvertMethod(_primitiveTypes[destType], srcType, destType, source); + } + + //try using type casting + try + { + return Expression.Convert(source, destType); + } + catch + { + // ignored + } + + if (!srcType.IsConvertible()) + throw new InvalidOperationException("Cannot convert immutable type, please consider using 'MapWith' method to create mapping"); + + //using Convert + if (_primitiveTypes.ContainsKey(destType)) + { + return CreateConvertMethod(_primitiveTypes[destType], srcType, destType, source); + } + + var changeTypeMethod = typeof(Convert).GetMethod("ChangeType", new[] { typeof(object), typeof(Type) }); + return Expression.Convert(Expression.Call(changeTypeMethod, Expression.Convert(source, typeof(object)), Expression.Constant(destType)), destType); + } + + private static bool IsObjectToPrimitiveConversion(Type sourceType, Type destinationType) + { + return (sourceType == typeof(object)) && _primitiveTypes.ContainsKey(destinationType); + } + + private static Expression CreateConvertMethod(string name, Type srcType, Type destType, Expression source) + { + var method = typeof(Convert).GetMethod(name, new[] { srcType }); + if (method != null) + return Expression.Call(method, source); + + method = typeof(Convert).GetMethod(name, new[] { typeof(object) }); + return Expression.Convert(Expression.Call(method, Expression.Convert(source, typeof(object))), destType); + } + protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) { throw new NotImplementedException(); @@ -50,5 +112,22 @@ protected override Expression CreateInlineExpression(Expression source, CompileA { throw new NotImplementedException(); } + + // Primitive types with their conversion methods from System.Convert class. + private static Dictionary _primitiveTypes = new Dictionary() { + { typeof(bool), "ToBoolean" }, + { typeof(short), "ToInt16" }, + { typeof(int), "ToInt32" }, + { typeof(long), "ToInt64" }, + { typeof(float), "ToSingle" }, + { typeof(double), "ToDouble" }, + { typeof(decimal), "ToDecimal" }, + { typeof(ushort), "ToUInt16" }, + { typeof(uint), "ToUInt32" }, + { typeof(ulong), "ToUInt64" }, + { typeof(byte), "ToByte" }, + { typeof(sbyte), "ToSByte" }, + { typeof(DateTime), "ToDateTime" } + }; } } diff --git a/src/Mapster/Adapters/RecordTypeAdapter.cs b/src/Mapster/Adapters/RecordTypeAdapter.cs index eb5bad66..b4e3c7e4 100644 --- a/src/Mapster/Adapters/RecordTypeAdapter.cs +++ b/src/Mapster/Adapters/RecordTypeAdapter.cs @@ -12,12 +12,9 @@ internal class RecordTypeAdapter : BaseClassAdapter { protected override int Score => -151; - protected override bool CanMap(Type sourceType, Type destinationType, MapType mapType) + protected override bool CanMap(PreCompileArgument arg) { - if (sourceType == typeof (string) || sourceType == typeof (object)) - return false; - - if (!destinationType.IsRecordType()) + if (!arg.DestinationType.IsRecordType()) return false; return true; diff --git a/src/Mapster/Adapters/StringAdapter.cs b/src/Mapster/Adapters/StringAdapter.cs new file mode 100644 index 00000000..a3d37793 --- /dev/null +++ b/src/Mapster/Adapters/StringAdapter.cs @@ -0,0 +1,67 @@ +using Mapster.Utils; +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace Mapster.Adapters +{ + internal class StringAdapter : PrimitiveAdapter + { + protected override int Score => -110; + protected override bool CheckExplicitMapping => false; + + protected override bool CanMap(PreCompileArgument arg) + { + return arg.SourceType == typeof(string) || arg.DestinationType == typeof(string); + } + + protected override Expression CreateExpressionBody(Expression source, Expression destination, CompileArgument arg) + { + var sourceType = arg.SourceType; + var destinationType = arg.DestinationType; + + if (sourceType == destinationType) + return source; + + if (destinationType == typeof(string)) + { + if (sourceType.GetTypeInfo().IsEnum) + { + var method = typeof(Enum<>).MakeGenericType(sourceType).GetMethod("ToString", new[] { sourceType }); + return Expression.Call(method, source); + } + else + { + var method = sourceType.GetMethod("ToString", Type.EmptyTypes); + return Expression.Call(source, method); + } + } + else //if (sourceType == typeof(string)) + { + if (destinationType.GetTypeInfo().IsEnum) + { + var method = typeof(Enum<>).MakeGenericType(destinationType).GetMethod("Parse", new[] { typeof(string) }); + return Expression.Call(method, source); + } + else + { + var method = destinationType.GetMethod("Parse", new[] { typeof(string) }); + if (method != null) + return Expression.Call(method, source); + } + } + + return base.ConvertType(source, arg); + } + + protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) + { + throw new NotImplementedException(); + } + + protected override Expression CreateInlineExpression(Expression source, CompileArgument arg) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Mapster/Compile/CompileArgument.cs b/src/Mapster/Compile/CompileArgument.cs index cf4df9b4..2f560291 100644 --- a/src/Mapster/Compile/CompileArgument.cs +++ b/src/Mapster/Compile/CompileArgument.cs @@ -7,6 +7,7 @@ public class CompileArgument public Type SourceType; public Type DestinationType; public MapType MapType; + public bool ExplicitMapping; public TypeAdapterSettings Settings; public CompileContext Context; } diff --git a/src/Mapster/Compile/PreCompileArgument.cs b/src/Mapster/Compile/PreCompileArgument.cs new file mode 100644 index 00000000..fe43fcef --- /dev/null +++ b/src/Mapster/Compile/PreCompileArgument.cs @@ -0,0 +1,12 @@ +using System; + +namespace Mapster +{ + public class PreCompileArgument + { + public Type SourceType; + public Type DestinationType; + public MapType MapType; + public bool ExplicitMapping; + } +} diff --git a/src/Mapster/Enums/AccessModifier.cs b/src/Mapster/Enums/AccessModifier.cs index 047de828..ffa93952 100644 --- a/src/Mapster/Enums/AccessModifier.cs +++ b/src/Mapster/Enums/AccessModifier.cs @@ -9,6 +9,7 @@ public enum AccessModifier Private = 1, Protected = 2, Internal = 4, + ProtectedInternal = 6, Public = 8, } } \ No newline at end of file diff --git a/src/Mapster/Mapster.csproj b/src/Mapster/Mapster.csproj index b7c01c53..7ca3ab53 100644 --- a/src/Mapster/Mapster.csproj +++ b/src/Mapster/Mapster.csproj @@ -62,12 +62,15 @@ + + + diff --git a/src/Mapster/TypeAdapter.cs b/src/Mapster/TypeAdapter.cs index 79cafeec..bf2f6f35 100644 --- a/src/Mapster/TypeAdapter.cs +++ b/src/Mapster/TypeAdapter.cs @@ -120,6 +120,10 @@ public static object Adapt(this object source, Type sourceType, Type destination { dynamic fn = config.GetMapFunction(sourceType, destinationType); return fn((dynamic)source); + + var fn = config.GetDynamicMapFunction(sourceType, destinationType); + return fn(source); + } /// diff --git a/src/Mapster/TypeAdapterConfig.cs b/src/Mapster/TypeAdapterConfig.cs index 493036b8..b3a0e7d8 100644 --- a/src/Mapster/TypeAdapterConfig.cs +++ b/src/Mapster/TypeAdapterConfig.cs @@ -27,11 +27,12 @@ private static List CreateRuleTemplate() new ClassAdapter().CreateRule(), //-150 new CollectionAdapter().CreateRule(), //-125 new DictionaryAdapter().CreateRule(), //-124 + new StringAdapter().CreateRule(), //-110 //fallback rules new TypeAdapterRule { - Priority = (srcType, destType, mapType) => -200, + Priority = arg => -200, Settings = new TypeAdapterSettings { //match exact name @@ -59,7 +60,7 @@ private static List CreateRuleTemplate() //dictionary accessor new TypeAdapterRule { - Priority = (srcType, destType, mapType) => srcType.GetDictionaryType()?.GetGenericArguments()[0] == typeof(string) ? -124 : (int?)null, + Priority = arg => arg.SourceType.GetDictionaryType()?.GetGenericArguments()[0] == typeof(string) ? -124 : (int?)null, Settings = new TypeAdapterSettings { ValueAccessingStrategies = @@ -91,7 +92,7 @@ public TypeAdapterConfig() this.Default = new TypeAdapterSetter(settings, this); this.Rules.Add(new TypeAdapterRule { - Priority = (sourceType, destinationType, mapType) => -100, + Priority = arg => -100, Settings = settings, }); } @@ -100,7 +101,18 @@ public TypeAdapterSetter When(Func canMap) { var rule = new TypeAdapterRule { - Priority = (srcType, destType, mapType) => canMap(srcType, destType, mapType) ? (int?)25 : null, + Priority = arg => canMap(arg.SourceType, arg.DestinationType, arg.MapType) ? (int?)25 : null, + Settings = new TypeAdapterSettings(), + }; + this.Rules.Add(rule); + return new TypeAdapterSetter(rule.Settings, this); + } + + public TypeAdapterSetter When(Func canMap) + { + var rule = new TypeAdapterRule + { + Priority = arg => canMap(arg) ? (int?)25 : null, Settings = new TypeAdapterSettings(), }; this.Rules.Add(rule); @@ -163,12 +175,12 @@ private TypeAdapterRule CreateTypeTupleRule(TypeTuple key) { return new TypeAdapterRule { - Priority = (sourceType, destinationType, mapType) => + Priority = arg => { - var score1 = GetSubclassDistance(destinationType, key.Destination, this.AllowImplicitDestinationInheritance); + var score1 = GetSubclassDistance(arg.DestinationType, key.Destination, this.AllowImplicitDestinationInheritance); if (score1 == null) return null; - var score2 = GetSubclassDistance(sourceType, key.Source, this.AllowImplicitSourceInheritance); + var score2 = GetSubclassDistance(arg.SourceType, key.Source, this.AllowImplicitSourceInheritance); if (score2 == null) return null; return score1.Value + score2.Value; @@ -181,7 +193,7 @@ private static TypeAdapterRule CreateDestinationTypeRule(TypeTuple key) { return new TypeAdapterRule { - Priority = (sourceType, destinationType, mapType) => GetSubclassDistance(destinationType, key.Destination, true), + Priority = arg => GetSubclassDistance(arg.DestinationType, key.Destination, true), Settings = new TypeAdapterSettings(), }; } @@ -282,13 +294,17 @@ internal MethodCallExpression GetProjectionCallExpression(Type sourceType, Type private Hashtable _dynamicMapDict; internal Func GetDynamicMapFunction(Type sourceType) + { + return (Func)GetDynamicMapFunction(sourceType, typeof(TDestination)); + } + internal Delegate GetDynamicMapFunction(Type sourceType, Type destinationType) { if (_dynamicMapDict == null) _dynamicMapDict = new Hashtable(); - var key = new TypeTuple(sourceType, typeof(TDestination)); + var key = new TypeTuple(sourceType, destinationType); object del = _dynamicMapDict[key] ?? AddToHash(_dynamicMapDict, key, tuple => Compiler(CreateDynamicMapExpression(tuple))); - return (Func)del; + return (Delegate)del; } internal LambdaExpression CreateMapExpression(TypeTuple tuple, MapType mapType) @@ -421,8 +437,15 @@ private LambdaExpression CreateMapToTargetInvokeExpression(Type sourceType, Type internal TypeAdapterSettings GetMergedSettings(TypeTuple tuple, MapType mapType) { + var arg = new PreCompileArgument + { + SourceType = tuple.Source, + DestinationType = tuple.Destination, + MapType = mapType, + ExplicitMapping = this.RuleMap.ContainsKey(tuple), + }; var settings = (from rule in this.Rules.Reverse() - let priority = rule.Priority(tuple.Source, tuple.Destination, mapType) + let priority = rule.Priority(arg) where priority != null orderby priority.Value descending select rule.Settings).ToList(); diff --git a/src/Mapster/TypeAdapterRule.cs b/src/Mapster/TypeAdapterRule.cs index e45eb99d..48442d9c 100644 --- a/src/Mapster/TypeAdapterRule.cs +++ b/src/Mapster/TypeAdapterRule.cs @@ -4,7 +4,7 @@ namespace Mapster { public class TypeAdapterRule { - public Func Priority; + public Func Priority; public TypeAdapterSettings Settings; } } \ No newline at end of file diff --git a/src/Mapster/TypeAdapterSetter.cs b/src/Mapster/TypeAdapterSetter.cs index 1fb615bb..e76f7ae3 100644 --- a/src/Mapster/TypeAdapterSetter.cs +++ b/src/Mapster/TypeAdapterSetter.cs @@ -500,9 +500,9 @@ public TypeAdapterSetter Include - sourceType == typeof(TDerivedSource) && - destinationType == typeof(TDerivedDestination) ? (int?)100 : null, + Priority = arg => + arg.SourceType == typeof(TDerivedSource) && + arg.DestinationType == typeof(TDerivedDestination) ? (int?)100 : null, Settings = Settings }); diff --git a/src/Mapster/Utils/ReflectionUtils.cs b/src/Mapster/Utils/ReflectionUtils.cs index 2f890ffd..e12e7912 100644 --- a/src/Mapster/Utils/ReflectionUtils.cs +++ b/src/Mapster/Utils/ReflectionUtils.cs @@ -13,23 +13,6 @@ internal static class ReflectionUtils { private static readonly Type _stringType = typeof (string); - // Primitive types with their conversion methods from System.Convert class. - private static Dictionary _primitiveTypes = new Dictionary() { - { typeof(bool), "ToBoolean" }, - { typeof(short), "ToInt16" }, - { typeof(int), "ToInt32" }, - { typeof(long), "ToInt64" }, - { typeof(float), "ToSingle" }, - { typeof(double), "ToDouble" }, - { typeof(decimal), "ToDecimal" }, - { typeof(ushort), "ToUInt16" }, - { typeof(uint), "ToUInt32" }, - { typeof(ulong), "ToUInt64" }, - { typeof(byte), "ToByte" }, - { typeof(sbyte), "ToSByte" }, - { typeof(DateTime), "ToDateTime" } - }; - #if NET40 public static Type GetTypeInfo(this Type type) { @@ -96,16 +79,6 @@ public static Type GetGenericEnumerableType(this Type type) return type.GetInterface(IsGenericEnumerableType); } - private static Expression CreateConvertMethod(string name, Type srcType, Type destType, Expression source) - { - var method = typeof (Convert).GetMethod(name, new[] {srcType}); - if (method != null) - return Expression.Call(method, source); - - method = typeof (Convert).GetMethod(name, new[] {typeof (object)}); - return Expression.Convert(Expression.Call(method, Expression.Convert(source, typeof (object))), destType); - } - public static object GetDefault(this Type type) { return type.GetTypeInfo().IsValueType && !type.IsNullable() @@ -118,86 +91,6 @@ public static Type UnwrapNullable(this Type type) return type.IsNullable() ? type.GetGenericArguments()[0] : type; } - public static Expression BuildUnderlyingTypeConvertExpression(Expression source, Type sourceType, Type destinationType, TypeAdapterSettings settings) - { - var srcType = sourceType.UnwrapNullable(); - var destType = destinationType.UnwrapNullable(); - - if (srcType == destType) - return source; - - //special handling for string - if (destType == _stringType) - { - if (srcType.GetTypeInfo().IsEnum) - { - var method = typeof (Enum<>).MakeGenericType(srcType).GetMethod("ToString", new[] {srcType}); - return Expression.Call(method, source); - } - else - { - var method = srcType.GetMethod("ToString", Type.EmptyTypes); - return Expression.Call(source, method); - } - } - - if (srcType == _stringType) - { - if (destType.GetTypeInfo().IsEnum) - { - var method = typeof (Enum<>).MakeGenericType(destType).GetMethod("Parse", new[] {typeof (string)}); - return Expression.Call(method, source); - } - else - { - var method = destType.GetMethod("Parse", new[] {typeof (string)}); - if (method != null) - return Expression.Call(method, source); - } - } - - if (destType.GetTypeInfo().IsEnum && srcType.GetTypeInfo().IsEnum && settings.MapEnumByName == true) - { - var method = typeof(Enum<>).MakeGenericType(srcType).GetMethod("ToString", new[] { srcType }); - var tostring = Expression.Call(method, source); - var methodParse = typeof(Enum<>).MakeGenericType(destType).GetMethod("Parse", new[] { typeof(string) }); - - return Expression.Call(methodParse, tostring); - } - - if (IsObjectToPrimitiveConversion(srcType, destType)) - { - return CreateConvertMethod(_primitiveTypes[destType], srcType, destType, source); - } - - //try using type casting - try - { - return Expression.Convert(source, destType); - } - catch - { - // ignored - } - - if (!srcType.IsConvertible()) - throw new InvalidOperationException("Cannot convert immutable type, please consider using 'MapWith' method to create mapping"); - - //using Convert - if (_primitiveTypes.ContainsKey(destType)) - { - return CreateConvertMethod(_primitiveTypes[destType], srcType, destType, source); - } - - var changeTypeMethod = typeof (Convert).GetMethod("ChangeType", new[] {typeof (object), typeof (Type)}); - return Expression.Convert(Expression.Call(changeTypeMethod, Expression.Convert(source, typeof (object)), Expression.Constant(destType)), destType); - } - - private static bool IsObjectToPrimitiveConversion(Type sourceType, Type destinationType) - { - return (sourceType == typeof(object)) && _primitiveTypes.ContainsKey(destinationType); - } - public static MemberExpression GetMemberInfo(Expression method, bool noThrow = false) { var lambda = method as LambdaExpression;