Я пытаюсь разрешить данные элемента, расположенные в исходном типе, в элемент в типе назначения, используя методологию Custom Value Resolver.Я внимательно следил за документацией на веб-сайте 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.MapFrom(Выражение>).Не существует явного преобразования ссылок из WebSite.Utilities.AutoMapper.DisplayIdResolver в AutoMapper.IMemberValueResolver.'.
Из примера, показанного на веб-сайте AutoMapper, выглядит так, как если бы метод Custom Value Resolver Resolve
разрешил сопоставление двух элементов, только если они принадлежат к одному типу.Но я гарантировал, что тип, возвращаемый из метода resolver, действительно является типом, ожидаемым целевым членом.
Весьма вероятно, что я не совсем уверен в обобщениях и что я делаю простую ошибку, ноЯ не смог понять, что это может быть, я потерял всю объективность здесь.Возможно ли то, что я делаю, или это не то, для чего разработан резольвер?
EDIT
Мистер Лучиан Баргаоану указал, что для 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.MapFrom(Выражение>).Не существует явного преобразования ссылок из 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 относительно того, как это будет упоминаться в вызове профиля CreateMap.
РЕДАКТИРОВАТЬ 3
Используя ссылку на примеры на 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));