Click here to Skip to main content
Click here to Skip to main content

PropertyMapper

, 22 Apr 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Get rid of trivial mapping between objects like mapping between obj1.City and obj2.Town or between properties with the same name

Introduction

How many times did you code trivial mapping like:

  Address myaddress = new Address {
    .Town = myPersonAddress.City,
    .Street = myPersonAddress.Street
  }

Town maps to City, and then in the next class Town is called Locality, in Dutch it maps to plaats or stad. Housenumber maps to Housnr or Nr or Number or whatever. Furthermore, why do we need to map properties with the same name (Street)).

All this mapping becomes annoying and in the case of this address example, I recently was surprised how many times I had to translate it from one type in this namespace to that (proxy) type in that namespace.

So the PropertyMapper was born. Given two objects, set the properties of the To-object with the values of the From object if their names are the same or if the property names are mapped to each other, but only when the property is not excluded from the mapping.

In other words, given the above example, we will map Town and City while Street is mapped automatically unless we exclude it.

Automatic mapping comes with a price because, instead of a one by one direct coupling, two property collections have to be mapped to each other. So there is a speed issue.

We can map by reflection, but that is a little slow, we can map using Emit, but the Emit language is not my kind of sport. So, we will map using Expressions. The getter of the From and the setter of the To are translated to a Func and an Action delegate, which are wrapped in a separate class. Mapping means calling these delegates directly through this class.

A mapping between properties of type one and two won’t change, and an Expression must be compiled. So we separate the creation of the mapping and the compiling of its expressions from the applying of the mapping. The method RegisterAMapping creates the mapping, the method Map applies the mapping.

Town to City is mapped by a property map. This property map is a dictionary with string keys and values. We make a dictionary entry City (key) _town (value) and one Town (key) _town (value). We map on value, in this case on _town (but you can use your own). For the registration of the mapping, it is of no importance if the map really exists. So if you add a dictionary entry City (Locality) _town (value), the From and To Type don’t need to have a Locality property. So you make big list of mapping for each ‘address entity’ which you can use over and over again.

Example:

  Dictionary<string, string> addresspropertiesmap = new Dictionary<string, string>();
  addresspropertiesmap.Add("City", "_town");
  addresspropertiesmap.Add("Town", "_town");
  addresspropertiesmap.Add("Locality", "_town");
  addresspropertiesmap.Add("ZipCode", "_zip");
  addresspropertiesmap.Add("Nr", "_housenr");
  addresspropertiesmap.Add("HouseNr", "_housenr");
  addresspropertiesmap.Add("PostalCode", "_zip");;

We registrate the mapping like:

  PropertyMapper.Mapper.RegisterAMapping(typeof(Address), typeof(Address2), addresspropertiesmap, "Address", "Address2");

After this registration, you can write:

  PropertyMapper.Mapper.Map(address, address3);

Where Values of address3 are set to the mapped properties of address, no matter whether that address has a Town property and address3 has a City one.

Is it Fast?

You can beat direct mapping in any way, but on my machine, mapping 100.000 times of address3 to address took an average of 127 milliseconds. Of course, this is without the creation of the mapping, but you can do that at startup.

Conversion

In my previous version, I hadn’t included conversion. If two types differ, you have to convert the value of the fromtype to the equivalent value of the totype.

A word of caution: bear in mind that a Property Mapper is not the way to go when dealing with advance casting scenarios. In these cases, leave automatic mapping for the properties involved for what it is and code the mapping yourself.

There are several standard ways to do conversion: by casting, by 'Convert', by 'TryParse' (in different variants) or by implementing an interface in a custom class like the IConvertible interface, to just call a few. The important difference between TryParse and Convert is that Convert raises an exception when conversion fails, while TryParse returns a false as a return value.

I added a ConversionMapperFactory that specifies a standard conversion for combinations of FromType to ToType. Per combination, you can choose between NoConversion, UseCast, UseConvert, UseTryParse and UseIConversion.

The latter one, the custom conversion, I must explain, the other ones speak for themselves. I decided not to use the IConvertible interface, because an Interface, by definition, means implementing all methods while you probably only want one or two. So I implemented another known technique.

The tricks is as follows:

 public Interface IConvertable{}
 public Interface IConvertable<T, R> : IConvertable{ 
   T Convert(R input);
 }

The non-generic interface is useless to implement because it holds no members, the generic one inherits from it. That means you can use reflection to search for the non generic one while finding the generic one. The IConvertable<T,R> interface has only one method, but in one class you can implement this interface multiple times each time with different concrete typing like:

 private class ConvertManager : IConversion<DateTime, string>, IConversion<DateTime, bool> 

This class implements only two conversion implementations from string to datetime and bool to datetime (which is nonsense) instead of implementing all in case I had decided to use the IConvertible interface.

We getting flexibility just by adding or removing specific typed IConvertable<T, R> interfaces, while maintaining the rigid nature of interfaces where you need to implement every interface method; in our case one!

How does the propertymanager know which interfaces are implemented? Of course, we can use Reflection, but needless to say, the invocation is done by Expressions. The core implementation is:

  //the class found through reflection
  //by searching on the non-generic IConvertable interface
  handlerType = handler.GetType(); 

  MethodInfo minfo = handlerType.GetMethods().Where(m => m.Name == "Convert").Where(mm =>
  {
    return fromType == mm.GetParameters()[0].ParameterType && toType == mm.ReturnType;
  }).First();

  var fromparameter = Expression.Parameter(fromType, "from");
  var toparameter = Expression.Parameter(toType, "to");
  var resultparameter = Expression.Parameter(toType, "result");
  var invocationExpression =
  Expression.Lambda(
    Expression.Block(
        Expression.Call(
            Expression.Convert(Expression.Constant(handler), handlerType),
                minfo, new ParameterExpression[] { fromparameter }
        )), fromparameter);
  return invocationExpressionCompile();

The ConvertDispatcher class has all the code.

For the rest, I should say explore the code.

What’s Next?

For my purpose, I didn’t need to make my Mapper class thread safe. Static methods should always take into account thread safety.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Member 3531622

Netherlands Netherlands
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinprofessionalVolynsky Alex23-Apr-14 10:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150327.1 | Last Updated 22 Apr 2014
Article Copyright 2014 by Member 3531622
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid