Files
mixtape/zero.Web/Mapper/DefaultMapper.cs
T
2020-04-17 15:51:11 +02:00

160 lines
3.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace zero.Web.Mapper
{
public class DefaultMapper : IMapper
{
MapCache Maps = new MapCache();
/// <inheritdoc />
public void Add<T>() where T : IMapperConfig, new()
{
T config = new T();
config.Configure(this);
}
/// <inheritdoc />
public void Add(Assembly assembly)
{
Type configType = typeof(IMapperConfig);
IEnumerable<Type> types = assembly.GetTypes().Where(t => t.IsAssignableFrom(configType));
foreach (Type type in types)
{
IMapperConfig config = (IMapperConfig)Activator.CreateInstance(type);
config.Configure(this);
}
}
/// <inheritdoc />
public TTarget Map<TSource, TTarget>(TSource source) where TTarget : class, new()
{
if (source == null)
{
return null;
}
return Map(source, new TTarget());
}
/// <inheritdoc />
public TTarget Map<TSource, TTarget>(TSource source, TTarget target) where TTarget : class, new()
{
if (source == null)
{
return target;
}
Maps.Call(source, target);
return target;
}
/// <inheritdoc />
public void CreateMap<TSource, TTarget>(Action<TSource, TTarget> map) where TTarget : class, new()
{
Maps.Add<TSource, TTarget>((source, target) => map((TSource)source, (TTarget)target));
}
/// <summary>
/// Internal mappings cache
/// </summary>
class MapCache : Dictionary<int, Dictionary<int, Action<object, object>>>
{
int Index = 0;
Dictionary<string, int> TypeMappings = new Dictionary<string, int>();
/// <summary>
/// Adds a new action for the mapping
/// </summary>
public void Add<TSource, TTarget>(Action<object, object> map)
{
int sourceKey = GetKeyForType(typeof(TSource));
int targetKey = GetKeyForType(typeof(TTarget));
if (!ContainsKey(sourceKey))
{
Add(sourceKey, new Dictionary<int, Action<object, object>>());
}
if (!this[sourceKey].ContainsKey(targetKey))
{
this[sourceKey].Add(targetKey, map);
}
}
/// <summary>
/// Get action from defined types
/// </summary>
public void Call<TSource, TTarget>(TSource source, TTarget target)
{
int sourceKey = GetKeyForType(typeof(TSource));
int targetKey = GetKeyForType(typeof(TTarget));
if (!ContainsKey(sourceKey) || !this[sourceKey].ContainsKey(targetKey))
{
return;
}
Action<object, object> result = this[sourceKey][targetKey];
result(source, target);
}
/// <summary>
/// Get stored key for this type
/// </summary>
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
{
/// <inheritdoc />
void Add<T>() where T : IMapperConfig, new();
/// <inheritdoc />
void Add(Assembly assembly);
/// <summary>
/// Map an object to the target type
/// </summary>
TTarget Map<TSource, TTarget>(TSource source) where TTarget : class, new();
/// <summary>
/// Map an object to the target type given an already existing target instance
/// </summary>
TTarget Map<TSource, TTarget>(TSource source, TTarget target) where TTarget : class, new();
/// <summary>
/// Create a mapping from source to target object
/// </summary>
void CreateMap<TSource, TTarget>(Action<TSource, TTarget> map) where TTarget : class, new();
}
}