У меня есть карта AutoMapper, которая определена следующим образом
CreateMap<DateTime?, DateString>()
.ForMember(dest => dest.Value, opt => opt.ResolveUsing(src => src.HasValue ? src.Value.ToString("yyyyMMdd") : String.Empty));
DateString
определена как таковая
public class DateString
{
public String Value { get; set; }
}
Свойство Value
является String
, которое представляет собойдата в формате yyyymmdd
, чтобы приспособиться к этому ожидаемому формату, я конвертирую мои даты, представленные в виде DateTime
типов, в String
в этом формате.
Карта выше вызвана другой картой, которая определенавот так
CreateMap<DateTimeDetails, PickupDetails>()
.ForMember(dest => dest.time, opt => opt.MapFrom(src => src));
Классы DateTimeDetails
и PickupDetails
определены как
public class DateTimeDetails
{
public Nullable<DateTime> Date { get; set; }
public String Time { get; set; }
public Int32 TimeZoneOffset { get; set; }
}
public class PickupDetails
{
public TimeString time { get; set; }
public DateString date { get; set; }
}
Итак, общий поток таков:
Когда DateTimeDetails
преобразованные в PickupDetails
, свойства PickupDetails.date
и DateTimeDetails.Date
автоматически сопоставляются без использования .ForMember()
и .MapFrom()
и вызывают карту DateTime? -> DateString
.
Где свойство DateString.Value
установлено на yyyymmdd
или String.Empty
в зависимости от того, имеет значение исходный объект Nullable<DateTime>
или нет.
Проблема, с которой я столкнулся,что если я сделаю TSource
для моей DateTime? -> DateString
карты, обнуляемой либо с Nullable<DateTime>
, либо с DateTime?
, AutoMapper не распознает подпись <TSource, TDestination>
и не сопоставит свойство PickupDetails.date
.Она выдаст ошибку
Error mapping types.
Mapping types:
DateTimeDetails -> PickupDetails
Type Map configuration:
DateTimeDetails -> PickupDetails
Property:
date
Если я сделаю свою карту более явной, например,
CreateMap<DateTime?, DateString>()
.ForMember(dest => dest.Value, opt => opt.ResolveUsing(src =>
{
if (src.HasValue)
{
return src.Value.ToString("yyyyMMdd");
}
else
{
return String.Empty;
}
}));
И попытаюсь проникнуть в логику распознавателя, я не достигну ни одной установленной точки останова.где-нибудь внутри распознавателя.
Единственный способ заставить его работать, это если я поменяю TSource
на ненулевой тип DateTime
и внедрю проверку != null
вместо проверки Nullable<DateTime>.HasValue
в троичном выражении для возврата вот так
CreateMap<DateTime, DateString>()
.ForMember(dest => dest.Value, opt => opt.ResolveUsing(src => src != null ? src.ToString("yyyyMMdd") : String.Empty));
В этом формате AutoMapper распознает подпись <TSource, TDestination>
и автоматически сопоставляет PickupDetails.date
с картой DateTimeDetails -> PickupDetails
.
Iне могу понять, где я ошибаюсь и почему TSource
для моей карты DateTime? -> DateString
не может быть Nullable<DateTime>
или DateTime?
и должно быть ненулевым DateTime
Здесь является репо для проблемы.Этот онлайн-компилятор не может запускать AutoMapper V7.0.1, поэтому V6.2.2 - это то, что используется, и поведение с 6.2.2 по-прежнему некорректно, но не совпадает с тем, что я испытываю в 7.0.1, который я объяснил вышев этом посте.
** РЕДАКТИРОВАТЬ 1: **
С помощью Люциана Баргаоану я узнал больше о том, что происходит с этим отображением.Ниже приведены планы выполнения для той же карты с тем же оператором .ForMember()
, единственное, что изменилось, это TSource
ДляНа карте, использующей Nullable<DateTime>
TSource
, выполняется блок if-else, который проверяет свойство $src
.Если null, он возвращает не экземпляр new
класса TDestination
, а только указатель на него, в результате чего свойство destObj.date
не устанавливается равным пустому экземпляру его типа, в котором он будет содержать .Value
свойство полного пути доступа destObj.date.Value
, destObj.date
просто установлено в ноль.
В чем я не уверен, так это в поведении платформы .Net Core, которое вставляет эту проверку if($src == null)
если лямбда работает с переменной Nullable<T>
или AutoMapper добавляет ее.Потому что, как вы можете видеть ниже для плана выполнения с правой стороны изображения выше, я пытаюсь обработать сценарий $src == null
самостоятельно.Но на данный момент я никогда не доберусь туда.
Я также не уверен, что ролл переменная $typeMapDestination
воспроизводит во всем AutoMapper, но сейчас я получаю ошибку Error mapping types.
для моей карты CreateMap<Nullable<DateTime>, DateString>()
.
Я думал, что это может быть из-за того, что блок if($src == null)
останавливает манипулирование / возврат переменной $typeMapDestination
, и поэтому свойство назначения, обозначенное в .ForMemeber()
, на самом деле никогда не "отображается", поэтому ошибка
Еще одно поведение, на которое стоит обратить внимание, это ненулевое DateTime -> DateString
отображение, если ему отправляется нулевое значение, несмотря на следующий блок кода
$resolvedValue = .Try {
.If($src != null) {
.Call $src.ToString("yyyyMMdd")
} .Else {
System.String.Empty
}
} .Catch(System.NullReferenceException) {
.Default(System.String)
} .Catch(System.ArgumentNullException) {
.Default(System.String)
};
что-то вызываеткоторые пытаются потерпеть неудачу и перейти к одному из двух блоков catch ниже.Часть else { System.String.Empty }
блока if / else не сработает.И destObj.date
будет равен нулю вместо нового экземпляра DateString
со свойством .Value
""
.