Картографирование с общим назначением не работает? - PullRequest
0 голосов
/ 20 февраля 2019

Я пытаюсь построить иерархию профилей сопоставления, чтобы упростить создание сопоставлений для новых объектов, которые вписываются в эту иерархию.Но у меня проблемы с получением некоторых сопоставлений для работы.Отображение, которое я добавил с использованием параметра универсального типа, похоже, не работает, когда это тип назначения, однако оно работает, когда это тип источника.

Рассмотрим следующие типы:

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));
}

Естьчто-то мне не хватает, чтобы сделать эту работу?Или мне придется каждый раз создавать эти явные отображения?


Как указывалось в ответе Скотта, проблема в конечном счете заключается в том, что интерфейс, которым ограничен универсальный параметр, не имеет настраиваемых свойств.Но Надер также обнаружил, что использование определенной перегрузки метода 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));
}

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Я пробовал много способов, но без шансов, но эта перегрузка просто работала с частными установщиками контрактов

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"));
        }
    }

Возможно, Джимми использовал результат более чем одним способом

0 голосов
/ 20 февраля 2019

Добавьте установщик к свойству Output IResponse.

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

Это общее ограничение будет определять способ преобразования целевого типа и, в свою очередь, свойствосчитается доступным для записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...