我有一项服务将枚举值包装在 SafeEnum 类型中,以便在不违反合同的情况下添加新的枚举值。
举个例子:
public class Customer
{
public int Id { get; set; }
public SafeEnum<CustomerType> Type { get; set; }
}
public class CustomerModel
{
public int Id { get; set; }
public CustomerModelType Type { get; set; }
}
使用AutoMapper从Customer映射到CustomerModel时,有没有办法自动从
SafeEnum<T>
映射到T'
,其中T
是包装类型,T'
是模型中的匹配类型?
我知道这可以通过配置每个相关的枚举类型来解决,但我正在寻找更优雅的解决方案。
首先你需要创建一个实现
IObjectMapper
接口的类。这个接口有两个方法
IsMatch(ResolutionContext context)
和
Map(ResolutionContext context, IMappingEngineRunner mapper)
当映射两个对象时,Automapper 在内部使用IsMatch
方法来确定
IObjectMapper
的给定实例是否可用于从源类型映射到目标类型。在
ResolutionContext
对象上,您拥有 SourceType、DestinationType、SourceValue、DestinationValue、MappingEngine 的一个实例以及其他可以帮助您确定是否可以使用当前映射器映射这两种类型的实例。Map方法负责两种类型之间的实际映射。
因此,在
IsMatch
方法上,您应该检查源类型或目标类型是否是包装类的实例。然后,在
Map
方法上,当从包装值映射时,您可以使用反射打开值,并使用 ResolutionContext 上提供的映射引擎将打开的值映射到它的目标类型,然后返回它。类似地,当从任何类型映射到包装类型时,您可以获得封闭的通用包装器的类型参数,使用解析上下文中提供的映射引擎从源类型映射到通用包装器所包含的类型,并将结果包装在适当类型的包装类的实例上。
最后,您需要在应用程序启动时配置 MappingEngine 时包含此映射器(这不适用于 Mapper 类的静态方法,因为您无法更改其上的默认映射器),如下所示:
var configuration = new ConfigurationStore(new TypeMapFactory(), new IObjectMapper[] { new WrapperMapper()}.Union(MapperRegistry.Mappers));
var engine = new MappingEngine(configuration);
MapperRegistry.Mappers
静态属性是所有默认 Automapper 映射器的集合。如果不包括这些,您将失去所有默认功能。最后,这是一个有效的小提琴:
https://dotnetfiddle.net/vWmRiY
它可能需要一些工作来适应您的特定用例,但总体思路就在那里。这可用于包装基本类型、复杂类型或自动映射器支持的任何类型。
public class ObjectWrapper<T>
{
private T _property;
public ObjectWrapper(T property) {
_property = property;
}
public static implicit operator ObjectWrapper<T>(T value)
{
return new ObjectWrapper<T>(value);
}
public static explicit operator T(ObjectWrapper<T> myObject)
{
return myObject._property;
}
}