using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using zero.Core.Entities; namespace zero.Web.Mapper { public class DefaultMapper : IMapper { MapCache Maps = new MapCache(); /// public void Add() where T : IMapperConfig, new() { T config = new T(); config.Configure(this); } /// public void Add(Assembly assembly) { Type configType = typeof(IMapperConfig); IEnumerable types = assembly.GetTypes().Where(t => t.IsAssignableFrom(configType)); foreach (Type type in types) { IMapperConfig config = (IMapperConfig)Activator.CreateInstance(type); config.Configure(this); } } /// public TTarget Map(TSource source) where TTarget : class, new() { if (source == null) { return null; } return Map(source, new TTarget()); } /// public TTarget Map(TSource source, TTarget target) where TTarget : class, new() { if (source == null) { return target; } Maps.Call(source, target); return target; } /// public IEnumerable Map(IEnumerable source) where TTarget : class, new() { IList target = new List(); foreach (TSource item in source) { target.Add(Map(item, new TTarget())); } return target; } /// public ListResult Map(ListResult source) where TTarget : class, new() { IList target = new List(); foreach (TSource item in source.Items) { target.Add(Map(item, new TTarget())); } return new ListResult(target, source.TotalItems, source.Page, source.PageSize) { Statistics = source.Statistics }; } /// public void CreateMap(Action map) where TTarget : class, new() { Maps.Add((source, target) => map((TSource)source, (TTarget)target)); } /// /// Internal mappings cache /// class MapCache : Dictionary>> { int Index = 0; Dictionary TypeMappings = new Dictionary(); /// /// Adds a new action for the mapping /// public void Add(Action map) { int sourceKey = GetKeyForType(typeof(TSource)); int targetKey = GetKeyForType(typeof(TTarget)); if (!ContainsKey(sourceKey)) { Add(sourceKey, new Dictionary>()); } if (!this[sourceKey].ContainsKey(targetKey)) { this[sourceKey].Add(targetKey, map); } } /// /// Get action from defined types /// public void Call(TSource source, TTarget target) { int sourceKey = GetKeyForType(typeof(TSource)); int targetKey = GetKeyForType(typeof(TTarget)); if (!ContainsKey(sourceKey) || !this[sourceKey].ContainsKey(targetKey)) { return; } Action result = this[sourceKey][targetKey]; result(source, target); } /// /// Get stored key for this type /// int GetKeyForType(Type type) { string name = type.FullName; if (TypeMappings.TryGetValue(name, out int key)) { return key; } int index = Index++; TypeMappings.Add(name, index); return index; } } } public interface IMapper { /// void Add() where T : IMapperConfig, new(); /// void Add(Assembly assembly); /// /// Map an object to the target type /// TTarget Map(TSource source) where TTarget : class, new(); /// /// Map an object to the target type given an already existing target instance /// TTarget Map(TSource source, TTarget target) where TTarget : class, new(); /// /// Map a list of objects to the target type /// IEnumerable Map(IEnumerable source) where TTarget : class, new(); /// /// Map a list result containing objects to the target type /// ListResult Map(ListResult source) where TTarget : class, new(); /// /// Create a mapping from source to target object /// void CreateMap(Action map) where TTarget : class, new(); } }