Click here to Skip to main content
13,763,464 members
Click here to Skip to main content
Add your own
alternative version

Stats

34.8K views
273 downloads
46 bookmarked
Posted 15 Mar 2015
Licenced MIT

TinyMapper: Yet Another Object to Object Mapper for .NET

, 15 Mar 2015
Rate this:
Please Sign up or sign in to vote.
TinyMapper is a quick object-object mapper for .NET

Introduction

TinyMapper is an object to object mapper for .NET. The main advantage is performance. TinyMapper allows easily map object to object, i.e. properties or fields from one object to another, for instance.

private static void MapPerson()
{
    TinyMapper.Bind<Person, PersonDto>();

    var person = new Person
    {
        Id = Guid.NewGuid(),
        FirstName = "John",
        LastName = "Doe",
        Email = "support@tinymapper.net",
        Address = "Wall Street",
        CreateTime = DateTime.Now,
        Nickname = "Object Mapper",
        Phone = "Call Me Maybe "
    };

    var personDto = TinyMapper.Map<PersonDto>(person);
}

Performance

Yes, this chapter has to be on the end. I believe most of you know what object mappers are, so let's talk about performance briefly.

We'll use the same Person class for the testing purpose.

public sealed class Person
{
    public string Address { get; set; }
    public string Email { get; set; }
    public string FirstName { get; set; }
    public Guid Id { get; set; }
    public string LastName { get; set; }
    public string Nickname { get; set; }
    public DateTime CreateTime { get; set; }
    public string Phone { get; set; }
}

PersonDto class is the same as the Person. We'll compare:

During the test, we create a Person class instance and map all properties on the PersonDto class.

private static void MeasureHandwritten()
{
    Person person = CreatePerson();

    Stopwatch stopwatch = Stopwatch.StartNew();

    for (int i = 0; i < Iterations; i++)
    {
        PersonDto personDto = MapHandwritten(person);
    }
    stopwatch.Stop();
    Console.WriteLine("Handwritten: {0}ms", stopwatch.Elapsed.TotalMilliseconds);
}

private static void MeasureTinyMapper()
{
    Person person = CreatePerson();
    TinyMapper.Bind<Person, PersonDto>();

    Stopwatch stopwatch = Stopwatch.StartNew();

    for (int i = 0; i < Iterations; i++)
    {
        var personDto = TinyMapper.Map<PersonDto>(person);
    }

    stopwatch.Stop();
    Console.WriteLine("TinyMapper: {0}ms", stopwatch.Elapsed.TotalMilliseconds);
}

private static void MeasureAutoMapper()
{
    Person person = CreatePerson();
    Mapper.CreateMap<Person, PersonDto>();

    Stopwatch stopwatch = Stopwatch.StartNew();

    for (int i = 0; i < Iterations; i++)
    {
        var personDto = Mapper.Map<PersonDto>(person);
    }
    stopwatch.Stop();
    Console.WriteLine("AutoMapper: {0}ms", stopwatch.Elapsed.TotalMilliseconds);
}

where CreatePerson

private static Person CreatePerson()
{
    return new Person
    {
        Id = Guid.NewGuid(),
        FirstName = "John",
        LastName = "Doe",
        Email = "support@tinymapper.net",
        Address = "Wall Street",
        CreateTime = DateTime.Now,
        Nickname = "Object Mapper",
        Phone = "Call Me Maybe "
    };
}

and MapHandwritten

private static PersonDto MapHandwritten(Person person)
{
    var result = new PersonDto
    {
        Id = person.Id,
        FirstName = person.FirstName,
        LastName = person.LastName,
        Email = person.Email,
        Address = person.Address,
        CreateTime = person.CreateTime,
        Nickname = person.Nickname,
        Phone = person.Phone
    };
    return result;
}

we repeat measurement 1 000 000 times.

 

Getting Started

TinyMapper is available thru nugen, so you can install as all NuGet package. for example through Package Manager Console.

Okay, we're ready to start. First of all, you've to Bind source type to target type, like this.

TinyMapper.Bind<Person, PersonDto>();

Now TinyMapper knows how to map Person object to PersonDto object. Finally, call

var personDto = TinyMapper.Map<PersonDto>(person);

and you'll get mapped object. Here's the full version.

So you have to do two steps:

  • Bind source type to the target type
  • Map source object to the target type
Quote:

Note: if you're multithreading an application, register all bindings on application start. While the application is running, you'll call only Map method. So, you'll get speed and thread safe.

TinyMapper can do the first step for you, i.e., you can just call Map and the result will be the same.

Quote:

Note: Be careful to call Map without Bind, it's not thread safe.

More Complex Example

Let's take a look at a more complex sample. For example, we have the following classes.

public sealed class PersonComplex
{
    public Address Address { get; set; }
    public DateTime CreateTime { get; set; }
    public IReadOnlyList<string> Emails { get; set; }
    public string FirstName { get; set; }
    public Guid Id { get; set; }
    public string LastName { get; set; }
    public string Nickname { get; set; }
}

public sealed class Address
{
    public string Phone { get; set; }
    public string Street { get; set; }
    public string ZipCode { get; set; }
}

and we don't want to map CreateTime and Nickname properties.

As you can see, we've just marked CreateTime and Nickname as ignored. Bind LastName from the source Surname to the target class and bind IList of emails to List

TinyMapper allows:

  • Ignore fields
  • Map one field to a different field
  • Map interface to exact type

Custom Mapping

For instance, we have the following classes:

public sealed class PersonCustomSource
{
    public IList<string> Emails { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public sealed class PersonCustomTarget
{
    public IList<string> Emails { get; set; }
    public string FullName { get; set; }
}

We want to map:

  • FirsName and LastName to FullName with the following convention "FirstName LastName"

TinyMapper supports TypeConverter, i.e., you can create your own TypeConverter for any type.

public sealed class PersonTypeConverter : TypeConverter
{
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(PersonCustomTarget);
    }

    public override object ConvertTo
    (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        var concreteValue = (PersonCustomSource)value;
        var result = new PersonCustomTarget
        {
            FullName = string.Format("{0} {1}", concreteValue.FirstName, concreteValue.LastName),
            Emails = new List<string>(concreteValue.Emails)
        };
        return result;
    }
}

The next step is to register the type converter. TypeConverter supports registration through attribute...

[TypeConverter(typeof(PersonTypeConverter))]
public sealed class PersonCustomSource
{
    public IList<string> Emails { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

...or code

TypeDescriptor.AddAttributes(typeof(PersonCustomSource), 
	new TypeConverterAttribute(typeof(PersonTypeConverter)));

Here's an additional sample of how to implement a type converter.

Under the Hood

It's a long story. In the next article, I'll describe in detail about how TinyMapper works. Internally, TinyMapper generates mapping code through ILGenerator. The mapping code looks almost the same as handwritten code. For instance, the following code was generated for Person to PersonDto mapping.

I hope you enjoyed it. Thanks for reading the article.

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Sergey Morenko
Software Developer (Senior)
United States United States
B.Sc. in Computer Science.

You may also be interested in...

Comments and Discussions

 
Questioncan it be used with entity framework Pin
ovisariesdk13-Oct-17 7:53
memberovisariesdk13-Oct-17 7:53 
AnswerRe: can it be used with entity framework Pin
Sergey Morenko26-Oct-17 11:32
professionalSergey Morenko26-Oct-17 11:32 
QuestionHow much faster than a dictionary and tuple? Pin
tugrulGtx20-Apr-17 3:02
membertugrulGtx20-Apr-17 3:02 
AnswerRe: How much faster than a dictionary and tuple? Pin
Sergey Morenko20-Apr-17 11:20
professionalSergey Morenko20-Apr-17 11:20 
GeneralRe: How much faster than a dictionary and tuple? Pin
tugrulGtx20-Apr-17 11:53
membertugrulGtx20-Apr-17 11:53 
SuggestionBut How? Pin
John B Oliver26-Mar-15 12:18
memberJohn B Oliver26-Mar-15 12:18 
GeneralRe: But How? Pin
Sergey Morenko26-Mar-15 22:14
professionalSergey Morenko26-Mar-15 22:14 
GeneralRe: But How? Pin
Ehsan Sajjad15-Mar-17 1:30
mvpEhsan Sajjad15-Mar-17 1:30 
QuestionThank you! Pin
Shabbazz19-Mar-15 18:13
professionalShabbazz19-Mar-15 18:13 
AnswerRe: Thank you! Pin
Sergey Morenko19-Mar-15 21:26
professionalSergey Morenko19-Mar-15 21:26 
QuestionThread Safety Pin
Denis Ibragimov16-Mar-15 13:51
professionalDenis Ibragimov16-Mar-15 13:51 
AnswerRe: Thread Safety Pin
Sergey Morenko17-Mar-15 0:29
professionalSergey Morenko17-Mar-15 0:29 
GeneralVery Nice Pin
Muhammad Essa Rind15-Mar-15 10:27
memberMuhammad Essa Rind15-Mar-15 10:27 
GeneralRe: Very Nice Pin
Sergey Morenko15-Mar-15 12:18
professionalSergey Morenko15-Mar-15 12:18 
Generalvery nice Pin
joyhen12312315-Mar-15 8:54
memberjoyhen12312315-Mar-15 8:54 
GeneralRe: very nice Pin
Sergey Morenko15-Mar-15 12:18
professionalSergey Morenko15-Mar-15 12:18 

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

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

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web04-2016 | 2.8.181112.3 | Last Updated 15 Mar 2015
Article Copyright 2015 by Sergey Morenko
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid