123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- using AutoMapper.QueryableExtensions;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- using VCommon.Reflection;
- using VCommon.VAutoMapper.Internals;
- namespace VCommon.VAutoMapper
- {
- public static class VAutoMapper
- {
- private static VAutoMapperConfiguration Config { get; } = new VAutoMapperConfiguration();
- private static readonly HashSet<Type> PolyfillTypes = new HashSet<Type>();
- static VAutoMapper()
- {
- foreach (var type in TypeFinder.AllTypes) ConfigMapping(type);
- FlushMapper();
- }
- internal static void FlushMapper() => Config.FlushMapper();
- internal static void ConfigMapping(Type type)
- {
- foreach (var autoMapFromAttribute in type.GetCustomAttributes<AutoMapFromAttribute>())
- {
- foreach (var f in autoMapFromAttribute.FromTypes) ConfigMapping(f, type);
- }
- foreach (var autoMapToAttribute in type.GetCustomAttributes<AutoMapToAttribute>())
- {
- foreach (var t in autoMapToAttribute.ToTypes) ConfigMapping(type, t);
- }
- }
- internal static void ConfigMapping(Type from, Type to)
- {
- var cfg = Config.CreateMap(from, to);
- var toProps = to.GetPublicInstanceProperties();
- var fromProps = from.GetPublicInstanceProperties();
- foreach (var toProp in toProps.Where(p => p.IsDefined(typeof(AutoMapperIgnoreAttribute))))
- {
- var toAttr = toProp.GetCustomAttribute<AutoMapperIgnoreAttribute>();
- if (toAttr.Direction == AutoMapperIgnoreDirection.Both || toAttr.Direction == AutoMapperIgnoreDirection.From) cfg.ForMember(toProp.Name, p => p.Ignore());
- }
- foreach (var fromProp in fromProps.Where(p => p.IsDefined(typeof(AutoMapperIgnoreAttribute))))
- {
- var fromAttr = fromProp.GetCustomAttribute<AutoMapperIgnoreAttribute>();
- if (fromAttr.Direction == AutoMapperIgnoreDirection.Both || fromAttr.Direction == AutoMapperIgnoreDirection.To) cfg.ForMember(fromProp.Name, p => p.Ignore());
- }
- foreach (var toProp in toProps.Where(p => p.IsDefined(typeof(AutoMapJsonConvertAttribute))))
- {
- PolyfillTypes.Add(to);
- //from.fromProp:string -deson-> to.toProp:obj
- var fromProp = from.GetProperty(toProp.Name);
- if (null == fromProp) continue;
- if (typeof(string) != fromProp.PropertyType) throw new VAutoMapperException($"Invalid json mapping attribute for [{from.FullName}.{fromProp.Name}] it must be string");
- // (object p) => JsonSerializer.Deserialize( (([type])p).[fromProp] ), [toProp].PropertyType )
- var dejson = JsonConvertHolder.GetDeserializationExpression(fromProp, toProp);
- var paramFrom = Expression.Parameter(typeof(object));
- var paramFromUnboxing = Expression.Convert(paramFrom, from);
- var callDeJson = Expression.Invoke(dejson, Expression.Property(paramFromUnboxing, fromProp.Name), Expression.Constant(toProp.PropertyType));
- var expression = Expression.Lambda<Func<object, object>>(callDeJson, paramFrom);
- var func = expression.Compile();
- cfg.ForMember(fromProp.Name, x => x.MapFrom(obj => func(obj)));
- }
- foreach (var fromProp in fromProps.Where(p => p.IsDefined(typeof(AutoMapJsonConvertAttribute))))
- {
- PolyfillTypes.Add(from);
- //from.fromProp:obj -json-> to.toProp:string
- var toProp = to.GetProperty(fromProp.Name);
- if (null == toProp) continue;
- if (typeof(string) != toProp.PropertyType) throw new VAutoMapperException($"Invalid mapping attribute on {to.FullName}.{toProp.Name} it must be string");
- // (object p) => JsonSerializer.Serialize( (([type])p).[fromProp] ))
- var json = JsonConvertHolder.GetSerializationExpression(fromProp, toProp);
- var paramFrom = Expression.Parameter(typeof(object));
- var paramFromUnboxing = Expression.Convert(paramFrom, from);
- var callJson = Expression.Invoke(json, Expression.Property(paramFromUnboxing, fromProp.Name));
- var expression = Expression.Lambda<Func<object, object>>(callJson, paramFrom);
- var func = expression.Compile();
- cfg.ForMember(fromProp.Name, x => x.MapFrom(obj => func(obj)));
- }
- }
- //---------------------------------------
- public static TD MapTo<TD>(this object from) => Config.Mapper.Map<TD>(from);
- public static TD MapTo<TF, TD>(this TF from, TD to) => Config.Mapper.Map(from, to);
- public static TD[] ProjectionToArray<TF, TD>(this IQueryable<TF> queryable)
- {
- return PolyfillTypes.Contains(typeof(TD))
- ? MiddleMapper<TD>.ProjectionToArray(queryable)
- : queryable.ProjectTo<TD>(Config.Config).ToArray();
- }
- public static TD ProjectionFirstOrDefault<TF, TD>(this IQueryable<TF> queryable)
- {
- return PolyfillTypes.Contains(typeof(TD))
- ? MiddleMapper<TD>.ProjectionToArray(queryable).FirstOrDefault()
- : queryable.ProjectTo<TD>(Config.Config).FirstOrDefault();
- }
- }
- }
|