【问题标题】:Allow mapping of dynamic types using AutoMapper or similar?允许使用 AutoMapper 或类似工具映射动态类型?
【发布时间】:2011-12-08 08:35:09
【问题描述】:

我已经开始在一个项目中使用https://github.com/robconery/massive,我想知道是否有任何映射工具可以支持动态到静态类型的映射?

我之前用过AutoMapper,AutoMapper支持吗?

我知道 AutoMapper 的 DynamicMap 功能,但是我相信这个功能是为了运行地图而无需先创建地图。在我下面的示例中,它不起作用。

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

【问题讨论】:

  • 查看this q以获得更完整的答案。
  • @LiamB,“AutoMapper 支持这个吗?” - 你的意思是具有相同/相似名称的属性之间的自动映射?还是您的映射更复杂?
  • @LeonidVasilyev 抱歉 - 我不确定,这个问题已经 4 岁了! :)
  • @LiamB,哇,确实是这样:)
  • 我不明白...据我所知,上面的代码是犯罪的。如果我看到动态以这种方式使用,我会对上述程序员的能力和所使用的库的质量产生严重的疑问。我意识到可能有一些特定领域的知识在问题中并不清楚,但仍然...... C#!= JavaScript。为什么任何 ORM 都会返回动态?糟糕!

标签: c# automapper massive


【解决方案1】:

AutoMapper 4.2.0 现在支持Dynamic/expando/dictionary mapping

使用此功能,您可以将 expando 对象映射到静态类型:

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

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

旧版本的 AutoMapper 不支持此功能(Massive 内部使用 ExpandoObject,但未提供它具有哪些属性),您说得对,Mapper.DynamicMap 用于映射而不创建映射配置。

如果你只是想要简单的映射,其实给自己写一个映射器并不难:

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);

【讨论】:

  • 今天下午我已经为此苦苦挣扎了几个小时+1。谢谢
  • @nemesv "[...]ExpandoObject which doesn't provide which properties it has)[...]" IDictionary<string, object> 所以你可以转换到这个接口和使用ContainsKey
  • 以防万一有人在寻找房产时遇到问题。 GetProperty(...) 默认情况下区分大小写。使用以下标志使其不区分大小写 .GetProperty(entry.Key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
  • 使用空配置不适用于集合。
【解决方案2】:

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

Slapper.AutoMapper 将动态数据映射到静态类型

它适用于dynamicDictionary&lt;A, B&gt;,这太棒了。

这是一个示例(取自上面的 URL),展示了它与 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" );
}

【讨论】:

  • 这适用于深层层次结构,但是啊.. _ 约定很糟糕.. :(
  • nooooooooo,我不是指您的方法的名称。我的意思是,与公认的答案不同,这是一个可以处理类结构中的深层层次结构(复杂的类结构与您的答案中的示例不同)的库,但它需要一定的“命名约定”才能工作。有关示例,请参见链接。
  • 抱歉,我应该多加注意! :) 我同意如果子动态类型是父级的属性会更好,所以你得到 Foo.Bar.Baz 而不是 Foo_Bar_Baz...
  • @nawfal 可以自定义“_”约定,例如Slapper.AutoMapper.Configuration.IdentifierConventions.Add( type =&gt; type.Name + "_Id" );,见randyburden.com/Slapper.AutoMapper
【解决方案3】:

假设您使用的框架返回ExpandoObject,您可以使用 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);

您可以使用ConstructUsing 方法创建任何类型的复杂映射..

【讨论】:

    【解决方案4】:

    单个对象:

    Mapper.Map<Product>(dynamicProduct);
    

    列表:

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

    示例(第 71 行):https://github.com/AutoMapper/AutoMapper/blob/master/src/UnitTests/DynamicMapping.cs

    【讨论】:

      猜你喜欢
      • 2017-12-23
      • 2016-08-13
      • 1970-01-01
      • 2016-08-11
      • 2018-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多