我正在尝试构建映射配置文件的层次结构,以简化为适合此层次结构的新对象创建映射。但我无法让一些映射工作。我使用泛型类型参数添加的映射在它是目标类型时似乎不起作用,但是当它是源类型时它可以工作。
考虑以下类型:
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));
}
有什么我不想让这项工作?或者我每次都必须创建那些显式映射?
正如Scott的回答所指出的,问题最终是泛型参数受约束的接口没有可设置的属性。但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));
}
我尝试了很多方法,但没有机会,但这种超载只适用于私人合同制定者
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"));
}
}
也许jimmy以多种方式使用结果
在Output
的IResponse
属性中添加一个setter。
public interface IResponse
{
string Output { get; set; }
}
它试图映射到IReponse
并且它无法设置属性,因为它不可写。
也许这不是你想要的,因为你不希望IResponse
拥有可写属性。但这就是为什么它没有被设定。
在这种情况下,我可以确定的唯一解决方法是创建一个实现IResponse
并具有可写属性的基本响应。
class ResponseBase : IResponse
{
public string Output { get; set; }
}
class FooResponse : ResponseBase
{
}
然后将通用约束更改为基类而不是接口:
abstract class BaseProfile<TSource, TDestination> : Profile
where TSource : IRequest
where TDestination : ResponseBase
该泛型约束将确定如何转换目标类型,以及该属性是否被视为可写。