views:

191

answers:

3

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?

A: 

IValueFormatter is a interface, and can be tacked on to your existing classes or used in conjunction with what ever library it came out of, it looks like ValueResolver is a class that may have a broader range of use... In different words, IValueFormatter is probably used to help you use your classes with the library it came from, while value resolver is designed to help you use their classes in your code.

Eric Fode
A: 

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)));
DanM
+1  A: 

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.

Jimmy Bogard
Thanks for your answer, Jimmy. Is there any documentation on how to use profiles? I've been working off the documentation on the codeplex site, but I didn't come across anything about profiles.
DanM
To answer my own question, I found a good example of how to use profiles: http://mhinze.com/automapper-in-nerddinner/
DanM
need some more blammo! in my code...
CRice