Почему AutoMapper имеет IValueFormatter, когда он имеет, казалось бы, гораздо более мощный ValueResolver?
Похоже, что IValueFormatter
принимает значение типа object
и возвращает значение типа string
, а ValueResolver<TSource, TDestination>
принимает значение любого типа и возвращает значение любого типа. Таким образом, он более гибкий. Также существует вопрос, что с ValueResolver
вам никогда не нужно указывать источник на определенный тип - вы определяете его явно в своем определении класса.
Учитывая это, зачем использовать IValueFormatter
? Делает ли это что-то, что нельзя сделать с помощью ValueResolver
? Я не понимаю, как это работает?
Ответы
Ответ 1
Большая разница заключается в том, что formatters могут применяться на уровне члена, профиля, типа и глобального уровня. Таким образом, вы можете сделать что-то вроде "ForSourceType.AddFormatter() в профиле и теперь blammo! Все ваши десятичные знаки теперь отображаются как деньги. Резольверы строго предназначены для пользовательского сопоставления элементов.
Ответ 2
Хорошо, думаю, я понял это:
-
При IValueFormatter
вход в метод FormatValue()
является фактическим значением. (Хорошо, технически, это объект ResolutionContext
, который позволяет вам получить значение с помощью свойства SourceValue
, но вы получите идею).
-
При ValueResolver
вход в метод ResolveCore()
- это весь источник (а не только исходное значение).
Итак, если вы хотите сделать какое-то преобразование между исходным значением и значением назначения, IValueFormatter
будет работать, только если тип назначения - string
, а ValueResolver
будет работать, только если ResolveCore()
метод "знает", какое свойство использовать (что не будет иметь место, если ваш резольвер является общим назначением, т.е. не применяется к определенному свойству).
Обход
К счастью, всегда есть MapFrom
, который обеспечивает гибкость, которой не хватает как с резольверами, так и с форматировщиками.
Интерфейс конвертера
Я закончил писать интерфейс, чтобы просто и гибко обрабатывать то, что, по моему мнению, является очень распространенным сценарием: двухсторонние преобразования...
public interface ITwoWayConverter<TInput, TOutput>
{
TOutput ConvertForward(TInput value);
TInput ConvertBackward(TOutput value);
}
Преобразователь примеров:
public class PhoneNumberToString : ITwoWayConverter<long, string>
{
public string ConvertForward(long value)
{
return string.Format("{0:(###) ###-####}", Convert.ToInt64(value));
}
public long ConvertBackward(string value)
{
return Convert.ToInt64(Regex.Replace(value, @"\D", string.Empty));
}
}
Использование примера:
Mapper.CreateMap<User, UserViewModel>()
.ForMember(dest => dest.PhoneNumber, opt => opt
.MapFrom(orig => new PhoneNumberToString().ConvertForward(orig.PhoneNumber)));
Ответ 3
IValueFormatter - это интерфейс и может быть привязан к вашим существующим классам или использоваться в сочетании с тем, что когда-либо было в библиотеке, похоже, что ValueResolver - это класс, который может иметь более широкий диапазон использования... В разных слова, IValueFormatter, вероятно, используется, чтобы помочь вам использовать ваши классы в библиотеке, из которой он пришел, а средство определения ценности разработано, чтобы помочь вам использовать их классы в вашем коде.