Почему 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, вероятно, используется, чтобы помочь вам использовать ваши классы в библиотеке, из которой он пришел, а средство определения ценности разработано, чтобы помочь вам использовать их классы в вашем коде.