我从旧版本的AutoMapper升级并转换了我的自定义解析器,但我很难过。
public class ProductMappingProfile : Profile
{
public ProductMappingProfile()
{
CreateMap<Product, ProductViewModel>()
.ForMember(
dest => dest.Model,
opt => opt.ResolveUsing<ModelNameResolver>(src => src.ModelId));
// won't compile
}
}
产品具有int? ModelId
属性且ProductViewModel具有string Name
属性。
public class ModelNameResolver : IValueResolver<short?, string, string>
{
private readonly InventoryService _inventoryService;
public ModelNameResolver(InventoryService inventoryService)
{
_inventoryService = inventoryService;
}
public string Resolve(short? source, string destination, string destMember, ResolutionContext context)
{
if (!source.HasValue)
return "n/a";
return _inventoryService.GetModel(source.Value)
.Name;
}
}
The type 'MyNamespace.Web.Resolvers.ModelCodeResolver' cannot be used as type parameter 'TValueResolver' in the generic type or method `'AutoMapper.IMemberConfigurationExpression<TSource,TDestination,TMember>.ResolveUsing<TValueResolver>()'`.
There is no implicit reference conversion from `'MyNamespace.Web.Resolvers.ModelCodeResolver'` to `'AutoMapper.IValueResolver<Data.Models.Product,Web.ViewModels.ProductViewModel,string>'`.
我做错了什么?我怀疑我误解了新的自定义解析器界面。
答案 0 :(得分:5)
IValueResolver接口应使用源对象类型,目标对象类型和目标成员类型进行参数化(应该是Resolve方法的类型)结果)。在你的情况下,参数应该是
IValueResolver<Product, ProductViewModel, string>
但是您正在创建使用
进行参数化的解析器 IValueResolver<short?, string, string>
short?
不是您的源对象类型
string
不是您的目标对象类型
你应该使用类似的东西:
public class ModelNameResolver : IValueResolver<Product, ProductViewModel, string>
{
private readonly InventoryService _inventoryService;
public ModelNameResolver(InventoryService inventoryService)
{
_inventoryService = inventoryService;
}
public string Resolve(Product source, ProductViewModel destination,
string destMember, ResolutionContext context)
{
var modelId = source.ModelId;
if (!modelId.HasValue)
return "n/a";
return _inventoryService.GetModel(modelId.Value).Name;
}
}
您的映射应该看起来像
var inventoryService = new InventoryService();
var modelNameResolver = new ModelNameResolver(inventoryService);
Mapper.Initialize(c =>
{
c.CreateMap<Product, ProductViewModel>()
.ForMember(dest => dest.Model, opt => opt.ResolveUsing(modelNameResolver));
});
当然,您可以向IoC容器询问型号名称解析器的实例。
更新:如果您希望在不同的源和目标数据类型之间重用解析器,那么您有两个选择:
如果你的解析器可以有无参数构造函数,那么你可以使用IMemberValueResolver
:
public class ModelNameResolver : IMemberValueResolver<object, object, int?, string>
{
// create or assign _inventoryService
// also note objects as source and destination
public string Resolve(object source, object destination,
int? sourceMember, string destMember,
ResolutionContext context)
{
if (!sourceMember.HasValue)
return "n/a";
return _inventoryService.GetModel(sourceMember.Value).Name;
}
}
用法
.ForMember(dest => dest.Model,
opt => opt.ResolveUsing<ModelNameResolver, int?>(src => src.ModelId)
第二个选项 - 不要使用解析器。只需使用MapFrom
和您的自定义类进行映射:
.ForMember(dest => dest.Model,
opt => opt.MapFrom(src => someClass.GetModelName(src.ModelId)));
someSlass应该包含通过id
获取模型名称的方法public string GetModelName(int? modelId)
{
if (!modelId.HasValue)
return "n/a";
return _inventoryService.GetModel(modelId.Value).Name;
}