Allow mapping of dynamic types using AutoMapper or

2019-01-10 02:07发布

问题:

I've started to use https://github.com/robconery/massive for a project, I wonder if there is any mapping tool that allows support for Dynamic to static type mapping?

I've used AutoMapper previously, does AutoMapper support this?

I am aware of the DynamicMap function from AutoMapper, however I believe this function is for running maps without creating the Map first. In my example below it does not work.

dynamic curUser = users.GetSingleUser(UserID);   
var retUser = Mapper.DynamicMap<UserModel>(curUser);
users.GetSingleUser(UserID); // returns a dynamic object

回答1:

AutoMapper 4.2.0 now supports Dynamic/expando/dictionary mapping

With this feature you can map to your expando objects to static types:

dynamic CurUser = _users.GetSingleUser(UserID);   
var config = new MapperConfiguration(cfg => { });
var mapper = config.CreateMapper();

var retUser = mapper.Map<UserModel>(CurUser);

Old versions of AutoMapper do not support this (Massive internally uses ExpandoObject which doesn't provide which properties it has), and you are right Mapper.DynamicMap is for mapping without creating mapping configuration.

Actually it's not hard to write yourself a mapper if you just want simple mapping:

public static class DynamicToStatic
{
    public static T ToStatic<T>(object expando)
    {
        var entity = Activator.CreateInstance<T>();

        //ExpandoObject implements dictionary
        var properties = expando as IDictionary<string, object>; 

        if (properties == null)
            return entity;

        foreach (var entry in properties)
        {
            var propertyInfo = entity.GetType().GetProperty(entry.Key);
            if(propertyInfo!=null)
                propertyInfo.SetValue(entity, entry.Value, null);
        }
        return entity;
    }
}

dynamic CurUser = _users.GetSingleUser(UserID);   
var retUser = DynamicToStatic.ToStatic<UserModel>(CurUser);


回答2:

Try Slapper.AutoMapper https://github.com/randyburden/Slapper.AutoMapper

Slapper.AutoMapper maps dynamic data to static types

It works for both dynamic and Dictionary<A, B> which is awesome.

Here's an example (taken from the URL above) showing how easily it works with Dictionary:

public class Person
{
    public int Id;
    public string FirstName;
    public string LastName;
}

[Test]
public void CanMapMatchingFieldNamesWithEase()
{
    // Arrange
    var dictionary = new Dictionary<string, object>
                            {
                                { "Id", 1 },
                                { "FirstName", "Clark" },
                                { "LastName", "Kent" }
                            };

    // Act
    var person = Slapper.AutoMapper.Map<Person>( dictionary );

    // Assert
    Assert.NotNull( person );
    Assert.That( person.Id == 1 );
    Assert.That( person.FirstName == "Clark" );
    Assert.That( person.LastName == "Kent" );
}


回答3:

Assuming framework you use returns ExpandoObject you can achieve some sort of dynamic mapping using AutoMapper:

Mapper.CreateMap<ExpandoObject, UserModel>()
    .ForAllMembers((options) => options.ResolveUsing((resolution) =>
        {
            var dictionary =  (IDictionary<string, object>) resolution.Context.SourceValue;
            return dictionary[resolution.Context.MemberName];
        }));
...
dynamic CurUser = _users.GetSingleUser(UserID);   
var retUser = Mapper.Map<UserModel>(CurUser);

You can create any sort of complex mapping using ConstructUsing methods..



回答4:

Single object:

Mapper.Map<Product>(dynamicProduct);

List:

Mapper.Map<List<Product>>(dynamicListOfProducts);

Example (line 71): https://github.com/AutoMapper/AutoMapper/blob/master/src/UnitTests/DynamicMapping.cs