【问题标题】:Dictionary <string,string> map to an object using Automapper字典 <string,string> 使用 Automapper 映射到对象
【发布时间】:2011-09-05 16:16:36
【问题描述】:

下面的代码只针对这个问题

我正在上课

public User class
{
 public string Name{get;set;}
 public string Age{get;set;
}

我有一本像

这样的字典
Dictionary<string,string> data= new Dictionary<string,string>(); 
data.Add("Name","Rusi");
data.Add("Age","23");

User user= new User();

现在我想使用AutomapperUser 对象映射到这个dictionary。 Automapper 映射对象的属性,但在我的例子中,有一个字典和对象。

所以,请建议我如何做到这一点

【问题讨论】:

标签: c# asp.net-mvc asp.net-mvc-3 dictionary automapper


【解决方案1】:

如果您的函数类型是“ExpandoObject”,这将起作用。

public EmpClass
{
   public string EmpName { get; set; }
   public int EmpId { get; set; }
}

this.CreateMap<IDictionary<string, object>, EmpClass>()
                .ForMember(dest => dest.EmpName, src => src.MapFrom(x => x["EmpName"]))
                .ForMember(dest => dest.EmpId, src => src.MapFrom(x => x["EmpId"]));

如果有帮助,请告诉我。

【讨论】:

  • 正如一些最近的答案所说,它是内置的。您不需要地图。
  • 如果您的属性名称相同,如果它们不同,或者如果有人需要将字典中的一个属性映射到另一个属性,它是内置的,在这种情况下,这种类型的映射器会有所帮助。如果在模拟返回响应的同时编写单元测试用例,您需要使用这种映射器将数据 moq 响应与实际的类对象映射,因为您的数据不会自动映射。
  • 是的,但这不是这里的问题。在单元测试中,您应该使用完全相同的映射器/代码。所以我不确定你在说什么。
【解决方案2】:

这个线程有点老了,但现在有如何在 automapper 上完成它而无需任何配置,如官方documentation 所述:

AutoMapper 无需任何显式配置即可映射到动态对象/从动态对象映射 (...) 同样,您可以直接从 Dictionary 映射到对象,AutoMapper 会将键与属性名称对齐。

更新:

以下代码显示了一个工作示例(带有单元测试)。

void Test()
{
    var mapper = new MapperConfiguration(cfg => { }).CreateMapper();
    var dictionary = new Dictionary<string, object>()
    {
        { "Id", 1 },
        { "Description", "test" }
    };

    var product = mapper.Map<Product>(dictionary);

    Assert.IsNotNull(product);
    Assert.AreEqual(product.Id, 1);
    Assert.AreEqual(product.Description, "test");
}

class Product
{
    public int Id { get; set; }
    public string Description { get; set; }
}

【讨论】:

  • 虽然文档声明它应该默认工作,但运行一个稍微简单的测试场景表明情况并非如此。这将导致运行时异常:var mapper = new MapperConfiguration(cfg =&gt; { }).CreateMapper(); var result = mapper.Map&lt;Dictionary&lt;String, String&gt;, StringAttribute&gt;(dict);
  • AutoMapper 文档很好。我刚刚更新了我的原始答案,提供了一个完整的单元测试示例,以确保代码也能正常工作。
【解决方案3】:

因为我刚刚偶然发现了这个问题,所以我想在当前版本的 AutoMapper 中添加这个答案(即使原来的问题已经很老了):

public class MyConfig
{
    public string Foo { get; set; }
    public int Bar { get; set; }
}
var config = new MapperConfiguration(cfg => {});
var mapper = config.CreateMapper();

var source = new Dictionary<string, object>
{
    ["Foo"] = "Hello",
    ["Bar"] = 123
};
var obj = mapper.Map<MyConfig>(source);
obj.Foo == "Hello"; // true

【讨论】:

  • 在我将它与 ForMember 一起使用后它不起作用 :(( 或者 formember 或映射字典。你知道为什么会这样吗?
【解决方案4】:

AutoMapper 映射对象的属性,不应该在这种情况下运行。在这种情况下,您需要反射魔法。您可以通过中间序列化作弊:

var data = new Dictionary<string, string>();
data.Add("Name", "Rusi");
data.Add("Age", "23");
var serializer = new JavaScriptSerializer();
var user = serializer.Deserialize<User>(serializer.Serialize(data));

如果你坚持使用 AutoMapper,你可以做一些类似的事情:

Mapper
    .CreateMap<Dictionary<string, string>, User>()
    .ConvertUsing(x =>
    {
        var serializer = new JavaScriptSerializer();
        return serializer.Deserialize<User>(serializer.Serialize(x));
    });

然后:

var data = new Dictionary<string, string>();
data.Add("Name", "Rusi");
data.Add("Age", "23");
var user = Mapper.Map<Dictionary<string, string>, User>(data);

如果您需要处理带有子对象的更复杂的对象层次结构,您必须问自己以​​下问题:Dictionary&lt;string, string&gt; 是在这种情况下使用的正确数据结构吗?

【讨论】:

  • 非常好的解决方案,特别是如果您使用有条件地将 JSON 对象解析为强类型(例如,JSON 项中的“TypeOf”属性可能属于一种或多种对象类型)。
  • @Darin 使用您的方法,遇到此问题(仅使用第一种方法):'System.Collections.Generic.Dictionary2[[System.Collections.Generic.Dictionary2+KeyCollection[[System.String, mscorlib, Version= 4.0.0.0,Culture=neutral,.....,[System.String,mscorlib,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089]],mscorlib,Version=4.0.0.0,Culture=neutral,PublicKeyToken =b77a5c561934e089]]' 不支持字典的序列化/反序列化,键必须是字符串或对象。
  • @marcos-jonatan-suriani 给出的解决方案(下图,2019 年 8 月 30 日)是“原生的”,更简单且更新了。
【解决方案5】:

AutoMapper 是一个非常灵活的解决方案。您可能可以使用自定义映射配置文件来实现这一点,例如:

public class UserMappingProfile : Profile
{
  // Props
  public override string ProfileName { get { return "UserMappingProfile"; } }

  // Methods
  public override void Configure()
  {
    CreateMap<User, Dictionary<string, string>>().ConvertUsing<DictionaryTypeConverter>();
    base.Configure();
  }

  // Types
  internal class DictionaryTypeConverter : ITypeConverter<User, Dictionary<string, string>>
  {
    public User Convert(ResolutionContext context)
    {
      var dict = context.SourceValue as Dictionary<string, string>;
      if (dict == null)
        return null;

      return new User() { Name = dict["Name"], Age = dict["Age"] };
    }
  }
}

有了这个,我可以创建一个映射器的自定义实例:

var config = new Configuration(new TypeMapFactory(), MapperRegistry.AllMappers());
config.AddProfile<UserMappingProfile>();

config.AssertConfigurationIsValid();

var mapper = new MappingEngine(config);

我可能会这样做:

var dict = new Dictionary<string, string> { { "Name", "Matt" }, { "Age", "27" } };
var user = mapper.Map<User, Dictionary<string, string>>(dict);

【讨论】:

    【解决方案6】:

    更简单的解决方案。只需从 KeyValuePair 映射您的对象。示例:

    CreateMap<KeyValuePair<Guid, string>, User>()
                .ForMember(u => u.Id, src => src.MapFrom(x => x.Key))
                .ForMember(u => u.Name, src => src.MapFrom(x => x.Value));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-13
      • 2011-08-25
      • 1970-01-01
      相关资源
      最近更新 更多