我正在尝试使用“自定义值解析器”方法将源类型中的成员数据解析为目标类型中的成员。我已尽可能仔细地关注AutoMapper网站http://docs.automapper.org/en/stable/Custom-value-resolvers.html上的文档。我已经仔细检查以确保我遵循提供的示例,但是有一个区别。源上的成员与目标上的成员类型不同。
IValueResolver.cs
public interface IValueResolver<in TSource, in TDestination, in TSourceMember, TDestinationMember>
{
TDestinationMember Resolve(TSource source, TDestination destination, TSourceMember sourceMember, TDestinationMember destinationMember, ResolutionContext context);
}
DisplayIdResolver.cs
public class DisplayIdResolver : IValueResolver<object, object, int, string>
{
// Seems like this may be useless unless its mapping to a destination member of the same type as the source member
public string Resolve(object source, object destination, int sourceMember, string destinationMember, ResolutionContext context)
{
if (source.GetType().Equals(typeof(Developer)))
{
return IdentifierType.ConvertToAppId(sourceMember, IdentifierType.DEVELOPER.Code);
}
. . . etcetera . . .
}
}
AutoMapperProfile.cs
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<Developer, DeveloperDetailModel>().ForMember(dest => dest.DisplayId, opt => opt.MapFrom<DisplayIdResolver, int>(src => src.DeveloperId));
}
}
从AutoMapperProfile构造函数的这一行代码中,我收到以下编译时错误:
类型'WebSite.Utilities.AutoMapper.DisplayIdResolver'不能为 在通用类型或方法中用作类型参数“ TValueResolver” 'IMemberConfigurationExpression <开发人员,DeveloperDetailModel, 字符串> .MapFrom
(Expression >)'。没有隐式引用转换 从“ WebSite.Utilities.AutoMapper.DisplayIdResolver”到 'AutoMapper.IMemberValueResolver '。
从AutoMapper网站上显示的示例来看,自定义值解析器Resolve
方法似乎仅允许两个成员具有相同类型的映射。但是我已经确保从resolver方法返回的类型确实是目标成员期望的类型。
很可能我对泛型感到困惑,并且我正在犯一个简单的错误,但是我无法弄清楚那是什么,我在这里失去了所有客观性。我正在做的事情是否可行,或者这不是解析器的设计目的?
编辑
Lucian Bargaoanu先生指出,在以下link下还有一个AutoMapper文档的备用站点。由于此新文档未提供接口示例,因此我可以假定IValueConverter
的接口为:
public interface IValueConverter<in TSourceMember, TDestinationMember>
{
TDestinationMember Resolve(TSourceMember sourceMember, TDestinationMember destinationMember, ResolutionContext context);
}
如果是这种情况,那么这将没有什么用,因为我确实需要源对象类型才能将源成员映射到目标成员。我也尝试过将其与其他对象参数一起用作源,但是ConvertUsing
方法没有具有3个参数的重载。我也看不到如何用新文档来完成此操作。
编辑2
建议我使用IMemberValueResolver。这就是我所做的:
IMemberValueResolver.cs
public interface IMemberValueResolver<in TSource, in TDestination, TSourceMember, TMember>
{
TMember Resolve(TSource source, TDestination destination, TSourceMember sourceMember, TMember destinationMember, ResolutionContext context);
}
DisplayIdResolver.cs
public class DisplayIdResolver : IMemberValueResolver<object, object, int, string>
{
public string Resolve(object source, object destination, int sourceMember, string destinationMember, ResolutionContext context)
{
if (source.GetType().Equals(typeof(Developer)))
{
return IdentifierType.ConvertToDisplayId(sourceMember, IdentifierType.DEVELOPER.Code);
}
... more type comparisons here, etc ...
return null;
}
}
AutoMapperProfile.cs
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<Developer, DeveloperDetailModel>().ForMember(dest => dest.DisplayId, opt => opt.MapFrom<DisplayIdResolver, int>(src => src.DeveloperId));
}
}
这会导致编译时错误:
类型'WebSite.Utilities.AutoMapper.DisplayIdResolver'不能为 在通用类型或方法中用作类型参数“ TValueResolver” 'IMemberConfigurationExpression <开发人员,DeveloperDetailModel, 字符串> .MapFrom
(Expression >)'。没有隐式引用转换 从“ WebSite.Utilities.AutoMapper.DisplayIdResolver”到 'AutoMapper.IMemberValueResolver '。
这太糟糕了,因为我真的想使用AutoMapper的所有功能。我遵循了使用IValueResolver
的更简单示例的示例,但该示例也不起作用。我将ASP.Net Core 2.2和AutoMapper.Extensions.Microsoft.DependencyInjection
库用于Automapper-以及本示例中刚刚包含的Profile类。完全按照网站上提供的文档,我无法在AutoMapper网站上使用最简单的情况下工作,也无法使更高级的IMemberValueResolver
案例下工作。该网站提供了实现类的示例,但没有提供接口的示例。该示例中的MapFrom调用似乎是不正确的,因为没有参数组合为我提供了.NET编译器将接受的语法。
请注意,我知道该错误指出以下内容:
不能用作类型参数'TValueResolver'
但您可以清楚地看到,我没有在任何地方使用IValueResolver
。我只是在类IMemberValueResolver
中实现DisplayIdResolver
接口,并按照AutoMapper网站上的示例 进行操作,以了解如何在Profile的CreateMap调用中对其进行引用。>
编辑3
使用link到Github上的示例,我能够找到我要完成的确切测试用例场景。但是,Github上的示例与我尝试编译的代码之间没有区别:
public class CustomResolver : IMemberValueResolver<object, object, int, int>
{
public int Resolve(object s, object d, int source, int dest, ResolutionContext context)
{
return source + 5;
}
}
protected override MapperConfiguration Configuration { get; } = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Source, Dest>()
.ForMember(dto => dto.SomeValue,
opt => opt.MapFrom<CustomResolver, int>(m => m.SomeOtherValue));
});
如您所见-他们正在使用通用接口来使用IMemberValueResolver
并使用我正在做的签名,除了返回值是字符串而不是整数,所以它变成了(如我所之前发布):
public interface IMemberValueResolver<in TSource, in TDestination, TSourceMember, TMember>
{
TMember Resolve(TSource source, TDestination destination, TSourceMember sourceMember, TMember destinationMember, ResolutionContext context);
}
但是,以与示例中相同的方式调用它会导致未编译的代码,如前所述(我已经两次发布了堆栈跟踪错误):
CreateMap<Developer, DeveloperDetailModel>().ForMember(dest => dest.DisplayId, opt => opt.MapFrom<DisplayIdResolver, int>( src => src.DeveloperId));