Okay, I think I've figured this out:
With an IValueFormatter
, the input to the FormatValue()
method is the actual value. (Okay, technically, it's a ResolutionContext
object that lets you get at the value using the SourceValue
property, but you get the idea).
With a ValueResolver
, the input to the ResolveCore()
method is the entire source (not just the source value).
So, if you want to do some kind of conversion between a source value and a destination value, an IValueFormatter
will only work if the destination type is a string
, and a ValueResolver
will only work if the ResolveCore()
method "knows" which property to use (which won't be the case if your resolver is general purpose, i.e., doesn't apply to a particular property).
Workaround
Fortunately, there is always MapFrom
, which provides the flexibility that is lacking with both resolvers and formatters.
Converter interface
I ended up writing an interface to simply and flexibly handle what I believe is a very common scenario: two-way conversions...
public interface ITwoWayConverter<TInput, TOutput>
{
TOutput ConvertForward(TInput value);
TInput ConvertBackward(TOutput value);
}
Example converter:
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));
}
}
Example usage:
Mapper.CreateMap<User, UserViewModel>()
.ForMember(dest => dest.PhoneNumber, opt => opt
.MapFrom(orig => new PhoneNumberToString().ConvertForward(orig.PhoneNumber)));