It looks like an IValueFormatter
takes a value of type object
and returns a value of type string
, while a ValueResolver<TSource, TDestination>
takes a value of any type and returns a value of any type. So, it's more flexible. There is also the matter that, with a ValueResolver
, you never need to cast the source to a particular type--you define it explicitly in your class definition.
Given this, why use IValueFormatter
? Does it do anything that can't be done with ValueResolver
? Am I misunderstanding how it works?
The big difference is that formatters can be applied at the member, profile, type and global level. So you can do something like "ForSourceType.AddFormatter() in a profile, and now blammo! All your decimals now show up as money. Resolvers are strictly for custom member mapping.
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)));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With