TinyMapper介绍

4 篇文章 0 订阅

原文:http://www.codeproject.com/Articles/886420/TinyMapper-yet-another-object-to-object-mapper-for

类似文章(Simple Model/Entity Mapper in C#) http://www.codeproject.com/Tips/807820/Simple-Model-Entity-mapper-in-Csharp,修改版本http://www.codeproject.com/Tips/885770/Simple-Model-Entity-Mapper-in-Csharp

核心代码如下:

public static class MapperUtility
{
    /*passing values to given object*/
    public static TTarget MapTo<TSource, TTarget>(this TSource aSource, TTarget aTarget)
    {
        const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
       
        /*TODO: find fields*/
        var srcFields = (from PropertyInfo aProp in typeof(TSource).GetProperties(flags)
                           where aProp.CanRead     //check if prop is readable
                             select new
                             {
                                 Name = aProp.Name,
                                 Type = Nullable.GetUnderlyingType(aProp.PropertyType) ?? aProp.PropertyType
                             }).ToList();
        var trgFields = (from PropertyInfo aProp in aTarget.GetType().GetProperties(flags)
                             where aProp.CanWrite   //check if prop is writeable
                                 select new
                                 {
                                     Name = aProp.Name,
                                     Type = Nullable.GetUnderlyingType(aProp.PropertyType) ?? aProp.PropertyType
                                 }).ToList();

        /*TODO: common fields where name and type same*/
        var commonFields = srcFields.Intersect(trgFields).ToList();

        /*assign values*/
        foreach (var aField in commonFields)
        {
            var value = aSource.GetType().GetProperty(aField.Name).GetValue(aSource, null);
            PropertyInfo propertyInfos = aTarget.GetType().GetProperty(aField.Name);
            propertyInfos.SetValue(aTarget, value, null);
        }
        return aTarget;
    }

    /*returns new object with mapping*/
    public static TTarget CreateMapped<TSource, TTarget>(this TSource aSource) where TTarget : new()
    {
        return aSource.MapTo(new TTarget());
    }
}
Student source = new Student() { Id = 1, Name = "Smith" };
/*get new object, which been mapped*/
StudentLog newMapped = source.CreateMapped<Student, StudentLog>();
/*mapp to existing object*/
StudentLog aSourceLog = new StudentLog();
Student target = new Student();
target.Id = 2;
target.Name = "Tom";

aSourceLog = target.MapTo(aSourceLog);
//or
target.MapTo(aSourceLog);




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 is object mappers, so let's talk about performance briefly.

We'll use the same Person class for 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 Person. We'll compare:

During test, we create a Persoclass 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 thru 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 target type
  • Map source object to target type

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

More complex example

Let's take a look more complex sample. For example, we've following class.

public sealed class PersonComplex
{
    public Address Address { get; set; }
    public DateTime CreateTime { get; set; }
    public List<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 map CreateTime and Nickname properties.

As you can see, we've just marked CreateTime and Nickname as ignored.

Under the hood

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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值