Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
chaowlert committed May 26, 2017
1 parent c436564 commit cb2b752
Show file tree
Hide file tree
Showing 19 changed files with 266 additions and 152 deletions.
8 changes: 4 additions & 4 deletions src/Mapster/Adapters/BaseAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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");
}
Expand Down
6 changes: 3 additions & 3 deletions src/Mapster/Adapters/BaseAfterMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
7 changes: 2 additions & 5 deletions src/Mapster/Adapters/ClassAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions src/Mapster/Adapters/CollectionAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/Mapster/Adapters/DelegateAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
7 changes: 2 additions & 5 deletions src/Mapster/Adapters/DictionaryAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
40 changes: 40 additions & 0 deletions src/Mapster/Adapters/ObjectAdapter.cs
Original file line number Diff line number Diff line change
@@ -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<T>();

// poco, object

//return (object)src.Adapt<T, T>();

// object, object

//if (src.GetType() == typeof(object))
// return src;
// return src.Adapt(src.GetType(), src.GetType());
}
}
}
85 changes: 82 additions & 3 deletions src/Mapster/Adapters/PrimitiveAdapter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using Mapster.Utils;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

Expand All @@ -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;
}
Expand All @@ -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);

Expand All @@ -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();
Expand All @@ -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<Type, string> _primitiveTypes = new Dictionary<Type, string>() {
{ 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" }
};
}
}
7 changes: 2 additions & 5 deletions src/Mapster/Adapters/RecordTypeAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
67 changes: 67 additions & 0 deletions src/Mapster/Adapters/StringAdapter.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
1 change: 1 addition & 0 deletions src/Mapster/Compile/CompileArgument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
12 changes: 12 additions & 0 deletions src/Mapster/Compile/PreCompileArgument.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace Mapster
{
public class PreCompileArgument
{
public Type SourceType;
public Type DestinationType;
public MapType MapType;
public bool ExplicitMapping;
}
}
1 change: 1 addition & 0 deletions src/Mapster/Enums/AccessModifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum AccessModifier
Private = 1,
Protected = 2,
Internal = 4,
ProtectedInternal = 6,
Public = 8,
}
}
3 changes: 3 additions & 0 deletions src/Mapster/Mapster.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@
<Compile Include="Adapters\BaseClassAdapter.cs" />
<Compile Include="Adapters\DelegateAdapter.cs" />
<Compile Include="Adapters\DictionaryAdapter.cs" />
<Compile Include="Adapters\ObjectAdapter.cs" />
<Compile Include="Adapters\RecordTypeAdapter.cs" />
<Compile Include="Adapters\StringAdapter.cs" />
<Compile Include="Attributes\AdaptIgnoreAttribute.cs" />
<Compile Include="Attributes\AdaptMemberAttribute.cs" />
<Compile Include="Compile\CompileArgument.cs" />
<Compile Include="Compile\CompileContext.cs" />
<Compile Include="Compile\CompileException.cs" />
<Compile Include="Compile\PreCompileArgument.cs" />
<Compile Include="Enums\EnumMappingStrategy.cs" />
<Compile Include="Enums\MemberSide.cs" />
<Compile Include="Interfaces\IApplyable.cs" />
Expand Down
4 changes: 4 additions & 0 deletions src/Mapster/TypeAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

}

/// <summary>
Expand Down
Loading

0 comments on commit cb2b752

Please sign in to comment.