我想实现一个基础的映射系统,类似于AutoMapper,但所有映射都是显式的,没有基于约定的映射。
为了做到这一点,我编写了一个类,它应该维护一个"映射"函数注册表,并在需要时查找它们,以将一个类型映射到另一个类型。我设想的用法是这样的:
在启动过程中的某个地方:
Mapper.Register<TypeA, TypeB>(typeA =>
{
var typeB = new TypeB()
{
Property1 = typeA.Property1
};
return typeB;
}
然后当我想执行映射时...
TypeA typeA = new TypeA();
TypeB typeB = Mapper.Map<TypeA, TypeB>(typeA);
目前我使用了一个Dictionary<Tuple<Type, Type>, Delegate>
来存储这个映射寄存器,但它并不像我所希望的那样工作...
public static class Mapper
{
private readonly static Dictionary<Tuple<Type, Type>, Delegate> Mappings = new Dictionary<Tuple<Type, Type>, Delegate>();
public static void Register<TSource, TDestination>(Func<TSource, TDestination> mappingFunction)
where TSource : class
where TDestination : class
{
Delegate mappingFunc;
if (Mappings.TryGetValue(new Tuple<Type, Type>(typeof (TSource), typeof (TDestination)), out mappingFunc))
Mappings[new Tuple<Type, Type>(typeof (TSource), typeof (TDestination))] = mappingFunction;
else
Mappings.Add(new Tuple<Type, Type>(typeof (TSource), typeof (TDestination)), mappingFunction);
}
public static TDestination Map<TSource, TDestination>(TSource src)
where TSource : class
where TDestination : class
{
Delegate mappingFunc;
if (!Mappings.TryGetValue(new Tuple<Type, Type>(typeof (TSource), typeof (TDestination)), out mappingFunc))
throw new Exception("Invalid mapping: no mapping found for requested types.");
var func = mappingFunc as Func<TSource, TDestination>;
if (func == null)
throw new Exception("Invalid mapping: no mapping found for requested types.");
return func.Invoke(src);
}
}
使用此代码时,注册映射正常工作,但从字典中检索映射失败,我认为这是由于 Map
方法中的第三行导致的:
Mappings.TryGetValue(new Tuple<Type, Type>(typeof (TSource), typeof (TDestination)), out mappingFunc)
这行代码总是无法通过测试,如果我理解正确,这是因为Tuple是引用类型,所以一个新的
Tuple<Type, Type>
实例,无论Item1
和Item2
是什么,都将永远不会匹配Dictionary
中的任何键。因此,Dictionary<Tuple<Type, Type>, Delegate>
不适合存储此映射注册表。在这种情况下,什么数据类型是适合的?