使用通用目标映射不起作用?

问题描述 投票:2回答:2

我正在尝试构建映射配置文件的层次结构,以简化为适合此层次结构的新对象创建映射。但我无法让一些映射工作。我使用泛型类型参数添加的映射在它是目标类型时似乎不起作用,但是当它是源类型时它可以工作。

考虑以下类型:

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));
}
c# generics automapper
2个回答
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"));
        }
    }

也许jimmy以多种方式使用结果


3
投票

OutputIResponse属性中添加一个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

该泛型约束将确定如何转换目标类型,以及该属性是否被视为可写。

© www.soinside.com 2019 - 2024. All rights reserved.