我正在尝试构建映射概要文件的层次结构,以简化为适合该层次结构的新对象创建映射的过程。但是我无法使某些映射正常工作。我使用通用类型参数添加的映射在目标类型时似乎不起作用,但是在源类型时有效。
请考虑以下类型:
public interface IRequest
{
string Input { get; }
}
public interface IResponse
{
string Output { get; }
}
public class SomeObject
{
public string Value { get; set; }
}
abstract class BaseProfile<TSource, TDestination> : Profile
where TSource : IRequest
where TDestination : IResponse
{
protected BaseProfile()
{
CreateMap<TSource, SomeObject>()
.ForMember(src => src.Value, opt => opt.MapFrom(dest => dest.Input));
CreateMap<SomeObject, TDestination>()
.ForMember(src => src.Output, opt => opt.MapFrom(dest => dest.Value));
}
}
我希望能够做到这一点,以便具体类型的配置文件可以使用此父配置文件中的映射,因此我可以定义以下内容:
class FooRequest : IRequest
{
public string Input { get; set; }
}
class FooResponse : IResponse
{
public string Output { get; set; }
}
class FooProfile : BaseProfile<FooRequest, FooResponse>
{
public FooProfile()
{
}
}
但是,到响应对象的映射根本不映射。
Mapper.Initialize(c => c.AddProfiles(typeof(FooProfile).Assembly));
var request = new FooRequest { Input = "FOO" };
var obj = Mapper.Map<SomeObject>(request); // this works
// obj.Value = "FOO"
var response = Mapper.Map<FooResponse>(obj); // this doesn't
// response.Output = null
似乎可以解决此问题,我必须复制我认为已经创建但使用具体类型的映射。
public FooProfile()
{
// Adding this works
CreateMap<SomeObject, FooResponse>()
.ForMember(src => src.Output, opt => opt.MapFrom(dest => dest.Value));
}
要进行这项工作,我缺少什么吗?还是我每次都必须创建那些显式映射?
正如斯科特的答案中指出的那样,问题最终是通用参数所约束的接口没有可设置的属性。但是Nader还发现,使用ForMember()
方法的特定重载是可行的。因此,我们不是直接绑定到成员,而是绑定到成员名称。可以满足我的需求。
protected BaseProfile()
{
CreateMap<TSource, SomeObject>()
.ForMember(src => src.Value, opt => opt.MapFrom(dest => dest.Input));
CreateMap<SomeObject, TDestination>()
.ForMember(nameof(IResponse.Output), opt => opt.MapFrom(dest => dest.Value));
}
答案 0 :(得分:3)
将设置器添加到Output
的{{1}}属性中。
IResponse
它正在尝试映射到public interface IResponse
{
string Output { get; set; }
}
,并且由于无法写而无法设置属性。
也许这不是您想要的,因为您不希望IReponse
具有可写属性。但这就是为什么它没有被设置的原因。
在那种情况下,我唯一可以确定的解决方法是创建一个实现IResponse
并具有可写属性的基本响应。
IResponse
然后将通用约束更改为基类,而不是接口:
class ResponseBase : IResponse
{
public string Output { get; set; }
}
class FooResponse : ResponseBase
{
}
该通用约束将确定目标类型的转换方式,进而确定该属性是否可写。
答案 1 :(得分:1)
我尝试了很多方法,但是没有机会,但是这种超载仅适用于私人合同制定者
abstract class BaseProfile<TSource, TDestination> : Profile
where TSource : IRequest
where TDestination : IResponse
{
protected BaseProfile()
{
CreateMap<TSource, SomeObject>()
.ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.Input));
CreateMap(typeof(SomeObject), typeof(TDestination))
.ForMember("Output", opt => opt.MapFrom("Value"));
}
}
也许吉米以多种方式使用结果