2017-08-10 71 views
0

我想将抽象类型的任意列表映射到共享相同基类型的任意一组属性。 这里是一些UnitTest代码,它目前失败了,我想成功。你能帮助我,得到一个通用的解决方案吗?Automapper:成员列表

这里是类:

public class Source 
{ 
    public string Name { get; set; } = "SomeName"; 
    public Dictionary<string, ValueType> SourceList { get; set; } = new Dictionary<string, ValueType>(); 
} 
public interface IDestination 
{ 
    string Name { get; set; } 
} 

public class Destination : IDestination  //And many other classes like this, with other properties inherited from ValueType 
{ 
    public string Name { get; set; } 

    public double DoubleValue { get; set; } 
    public int IntValue { get; set; } 

    public string SomeOtherProperty { get; set; } 
} 

,这里是单元测试,我想成功:

[TestMethod] 
    public void TestMethod1() 
    { 
     var source = new Source(); 
     source.SourceList.Add("IntValue", (int) 3); 
     source.SourceList.Add("DoubleValue", (double) 3.14); 

     Mapper.Initialize(config => 
     { 
      //Put in some magic code here!!! 
     }); 

     var destinationAbstract = Mapper.Map<Source, IDestination>(source);  //the type of destination is known only at runtime. Therefore Mapping to Interface 

     var destination = (Destination) destinationAbstract; 
     Assert.AreEqual(source.Name, destination.Name); 
     Assert.AreEqual((int)source.SourceList["IntValue"], destination.IntValue); 
     Assert.AreEqual((double)source.SourceList["DoubleValue"], destination.DoubleValue); 
    } 

请注意,这

  • 数的类,继承自IDestination仅在运行时已知
  • 在SOURCELIST的内容可以为每个源实例是不同的,因此目标类的属性,也可以改变每一个类定义

我希望你能帮助我,因为我无法确定通用解决方案在文档的帮助下。

在此先感谢。

回答

0

默认情况下,您可以从Dictionary<string, object>(属性名称到属性值)映射到某个类,而不需要任何额外的配置。 docstests

+0

感谢您的回答。据我所知,这种映射只适用于源类型Dictionary ,没有其他Dictionary类型。如果我是对的,这对我的Dictionary 有什么帮助? (注意:ValueType只是任何自定义基类型的一个示例) – Hardy

+0

我尝试使用Dictionary 的映射,但存在两个问题:1.)我的源类型是Dictionary 和我不想投反对票。和2.)我的目标类型也包含其他成员,这些成员不是从源词典中读取的。 – Hardy

+0

为什么不呢?关于第二点,源词典中具有匹配目标属性的所有条目都将被映射,所以我不确定你的意思。 –

0

后考虑Lucians提示,并与Automapper尝试不同的事情后,我终于找到了我最初的单元测试的解决方案:

[TestMethod] 
    public void TestMethod1() 
    { 
     var source = new Source(); 
     source.SourceList.Add("IntValue", (int) 3); 
     source.SourceList.Add("DoubleValue", (double) 3.14); 

     Mapper.Initialize(config => 
     { 
      //"Magic code" 
      config.CreateMap<Source, IDestination>(); 
      config.CreateMap(typeof(Source), typeof(Destination)).IncludeBase(typeof(Source), typeof(IDestination)); 
     }); 

     //standard map-call 
     var destination = Mapper.Map<Destination>(source); 
     //Additional "Trick": 
     Dictionary<string, object> mappingDict = 
      source.SourceList.ToDictionary(pair => pair.Key, pair => (object) pair.Value); 
     Mapper.Map(mappingDict, destination, typeof(Dictionary<string, object>), typeof(Destination)); 

     Assert.AreEqual(source.Name, destination.Name); 
     Assert.AreEqual(source.SourceList["IntValue"], destination.IntValue); 
     Assert.AreEqual(source.SourceList["DoubleValue"], destination.DoubleValue); 
    } 

的“绝招”是投我Dictionary<string, ValueType>Dictionary<string,object>和映射此字典成员到目标对象另外(!)到标准地图调用。 这工作,但也有一些缺点:

  1. 映射验证是不可能的(验证说:要么源构件“SOURCELIST”没有被映射或目的地成员“的doubleValue”或“INTVALUE”未映射)
  2. 铸字典是有点丑(对我来说似乎没有必要......)
  3. 我需要2个调用Mapper.Map而不是只有一个。

在我看来,没有其他方法可以解决我最初的问题。但我愿意为我的解决方案提供任何建议或改进。 最初的问题也可以很容易地通过使用反射来解决,所以适当的映射设置的所有信息应该是存在的,但我无法找到适当的映射设置。

+0

关于验证,您可以通过定义仅具有静态成员的源接口来获取它。 –