Click here to Skip to main content
15,884,739 members
Articles / Programming Languages / C#
Tip/Trick

H-Mapper

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
5 Nov 2016CPOL3 min read 11.2K   2  
Introduction to H-Mapper

Introduction

This article describes briefly the features of H-Mapper, which is a .NET library available in Nuget written by me.

More information can be found at https://minhlhuong.wordpress.com/hmapper/.

Background

Mapping from one object to another is a task that many developers have to do in back-end developments. Many mappers already automate this task for them, so why use another one again? This is one of the purposes of this document.

Benefits

So here is what H-Mapper may do better than others:

  • Performance
  • Specify inclusions
  • Strongly type mapping declaration of generic types.

Performance

Some performance tests have been done in various configurations, and the results are displayed here:

Specify Inclusions

When dealing with large objects, and especially when they contain collections, it is often a bad idea to map the whole thing, so developers tend to create a lighter version of the target class. Instead of doing that, H-Mapper offers another possibility. Use the same target type, but specify the objects to include at execution time.

Strongly Type Mapping Declaration of Generic Types

When declaring a mapping for generic classes, other mappers have no other way than propose the use of the "typeof" method. Alas, in this case, it is not possible to benefit from the intellisense of Visual Studio. Also, it is hard to map a property to a custom delegate in such cases. H-Mapper offers a way to map generic types in a strongly typed manner.

Using the Code

First of all, let's declare a simple mapping. This is done in a static method of the MapConfig class.

C++
MapConfig.Initialize(initializer =>
{
   initializer.Map<Class1, DTO.Class1>();
}

In this document, I omit the namespace when I refer to the source type. The target type is prefixed by "DTO".

We can now map an instance of the source type in this way:

C++
var source = new Class1();
var MyDTO  = Mapper.Map<Class1, DTO.Class1>(source);

We can also fill an existing instance of the target type:

C++
Mapper.Fill<Class1, DTO.Class1>(source, target);

We can specify "object" as the type of the source object, and then create an extension method that omits the type of the source instance, but keep in mind that it comes with a loss of performance.

C++
public static TTarget Map<TTarget>(this object source)
{
   return Mapper.Map<object, TTarget>(source);
}

We can decide to map a property to another one when the names don't match.

C++
initializer.Map<Class1, DTO.Class1>()
    .WithMember(x => x.Key, api => api.LinkTo(x => x.Id))

Or, even a custom delegate or lambda expression.

C++
.WithMember(x => x.Date_Plus_2, api => api.LinkTo(x => x.Date.AddDays(2)))

Specify Inclusions

Now, here is how we specify inclusions:

C++
var myDTO = Mapper.Map<Class1, DTO.Class1>(source, 
    x => x.Coll.Select(y => y.CollProp), x => x.Prop);

In this example, we tells the mapper that we want to include Coll property, which is a collection type, and include CollProp property of the collection as well. We can specify the inclusions one after the other. In our example, Prop property is also retrieved. All other properties will be ignored.

Declare Mapping for Generics

Here is how we declare mapping for generics.

C++
initializer.Map<Business.SimpleGeneric2<TGen1>, DTO.SimpleGeneric2<TGen1>>()
   .WithMember(x=>x.AnotherGenericProperty, api => api.LinkTo(x=>x.GenericProperty))

H-Mapper offers special Argument types TGen1,..TGen9 we can use to map generic types. They all derive from IGeneric. We can also create our own IGeneric should we need to add constraints on the generic argument.

We can even map a property to a lambda expression, which is quite impossible with the other mappers. The delegate could be as fancy as :

C++
.WithMember(x=>x.Prop, 
   api=>api.LinkTo(arr=>arr.Select(item => new Class2() { Prop2=5}).ToArray()));

The returned type is an array of Class2, which will then be mapped to a collection of DTO.Class2 (depending on the type of the collection in the target type).

Mapping An Unknown Target Type

If we don't know in advance what the type of the target is, we can specify Object as the target type.

C++
object source; // coming from somewhere.
object target = Mapper.Map<object, object>(source);

The target type will then be taken from the first target type matching the type of the source object. If more than one type matches the source type, expect to have the result to be "random"..

This is specially useful when the target type is an ArrayList (which is a collection of objects).

Mapping a Whole Class to a Lambda Expression

This can be done with the ManualMap method:

C++
initializer.ManualMap((ManuallyMappedClass x) => Tuple.Create(x.Id, x.Title));

In this example, we map a class to a Tuple.

This is specially useful when we want to use a converter for enums:

C++
initializer.ManualMap((MyEnum val) => DTO.Convert(val));

Other Features

H-Mapper also supports many other things like polymorphism (with no extra configuration), enum, struct, circular references.

History

  • First release

License

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


Written By
Architect
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --