Automapper: Value Modifiers proposal

Created on 30 Jun 2016  Â·  16Comments  Â·  Source: AutoMapper/AutoMapper

In the 4.x timeframe, I removed a feature called "Formatters". Formatters were a way for you to modify the value of a string, and they stacked on top of each other.

We were using it on a project and it was a horrible idea, BUT I think the general idea might be valid. Type converters globally apply to everything to go from Type A to B, and value resolvers work with individual properties, but nothing really allows you to selectively apply a modifier between resolution and assignment.

Our mapping today works like:

source.Member = Resolve(dest)

Where the resolving could be a value resolver, a MapFrom, a member chain, hardcoded value etc.

But there's nothing that lets you take the value from resolving and apply any transforms.

Maybe this is called a transform?

Anyway, the idea is similar to formatters. I killed them originally because they were horribly slow (now could be fast), and our team was horrrrrribly abusing them.

Transformers are like type converters, but can be applied to non-type-map contexts:

  • Members
  • Profiles
  • Configuration

And at the Configuration level, we can apply conditions to them.

cfg.CreateMap<Source, Dest>()
    .ForMember(dest => dest.Name, opt => opt.Modify(srcVal => srcVal + " is handsome"));
cfg.CreateProfile("Foo", p => {
   p.Modify<string, string>(srcVal => srcVal + " is VERY handsome");
   p.CreateMap<InnerSource, InnerDest>();
});
cfg.Modify<string, string>(srcVal => srcVal + ". For realz");
cfg.Modify<string, string>(srcVal => srcVal, pm => pm.SourceMember.ContainsAttribute(typeof(SkipJunkAttribute)));

Modifiers would be applied first at the member, then profile, then configuration level. You can't opt-out, you'd need to segregate by profiles or add a condition.

Naming?

  • Modifiers
  • Transformers
Feature

Most helpful comment

I agree with @jbogard 's initial proposal here, being able to apply these at different levels of the hierarchy. From a user's perspective, I think I prefer that to contextual TypeConverters with conditions.

Personally, I find ApplyTransform() to be a more natural-sounding and explicit name than Modify().

All 16 comments

I would think maybe what you want to do is make this based on ExpressionVisitor that only apply to the Profiles and nothing else. I guess you could modify on Members, and configuration is just the default profile.

Then you can make the API use this to take cfg.Modify<T1,T2>(Expression<Func<T1, T2, T2>>) and make an ExpressionAssignmentVisitor that looks for those types in an assignable expression and then ReplaceParameters of assign from destination. This example needs some tweaking in what you want to do but the idea is there.
Also for type map modifies this could use the same based code except check the base class the properties are coming from and see if they match too. I don't like this idea because they can just use MapFrom to get the same result.

Then from that you make all these populate a PostExpressionVisitors list that gets applied to every type map in a profile when TypeMapPlanBuilder builds the expression out. The PostExpressionVisitors can be exposed in IProfile, but not recommended except for advance usages. Advance usages might be things like remove Try Catches, remove null checks, and maybe add before/after map globally for debugging purposes.

I don't see it :) There are deep debates on the intertubes about Resolve and MapFrom. And now this is different? I mean if you have a resolver, you can do what you want with it. And if you have a type converter, you can have it in any profile/configuration you want. So it's yet another feature, but I don't see the value. Sorry if I made too much noise, but that's my first reaction :)

@lbargaoanu I wouldn't use this (probably) either. The thing with type converters though - they're global. You put it in a profile, it still applies it _everywhere_. And value resolvers squash whatever config you have. Like the original example, you can't combine MapFrom with any other custom mapping logic, that is, do a redirect from this other property AND apply this transform.

Clearer now :) You can separate configuration by hand, so it doesn't have to be global. I guess the second point means you could reuse stuff. But I think people might want to be in complete control. Anyway, I see something :), but I don't know. If you want to say that it's another feature and if you don't like it don't use it, I guess that's understandable. But I would say it adds to the baggage. Maybe a regular user wouldn't see it this way.

Another option would be not to add another thing, but allow type converters to be contextual.

So to have a type converter only apply for that profile.

Right, and allow conditions to a type converter like I just added for property maps.

That sounds better to me. I mean start from here and see where it goes. Baby steps :)

TypeConverters, and possibly ValueResolvers being tied to just the profile would be best option I think.

But Hey I don't use this feature either, so I'm sure once you change this, you'll have a bunch of people have issues with it.

Conditions I'm still eeeeh on. You should be conditioning this by setting up profiles correctly. But again someone will be like that's too inconvenient for me.

With conditions, you don't have to come up with for example a hierarchy of
profiles for composed configuration. Do this, but DONT do that sort of
thing.

On Fri, Jul 1, 2016 at 10:26 AM, Tyler Carlson [email protected]
wrote:

TypeConverters, and possibly ValueResolvers being tied to just the profile
would be best option I think.

But Hey I don't use this feature either, so I'm sure once you change this,
you'll have a bunch of people have issues with it.

Conditions I'm still eeeeh on. You should be conditioning this by setting
up profiles correctly. But again someone will be like that's too
inconvenient for me.

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/1414#issuecomment-229976056,
or mute the thread
https://github.com/notifications/unsubscribe/AAGYMnAL7Zfk2Puof7iORQDXzMR5ot3Oks5qRTG2gaJpZM4JCSCl
.

Maybe Modify still has to exist, cause if you want to do conditions where you want to pass the property map over, your type converter won't be able to call these conditions if you map the types directly, instead of a property of another class.

I don't expect anyone to do this, but you never know.

I got #1420 to do predicates based on PropertyMaps.

Another option is make TypeConverter logic throw exception if source type and destination type are the same. It says you can't do this, please use TransformPropertyMap instead.

A year and no one else has asked for anything close to this. Meh.

I agree with @jbogard 's initial proposal here, being able to apply these at different levels of the hierarchy. From a user's perspective, I think I prefer that to contextual TypeConverters with conditions.

Personally, I find ApplyTransform() to be a more natural-sounding and explicit name than Modify().

Tracked by #2367.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings