2017-08-10 54 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

關於驗證,您可以通過定義僅具有靜態成員的源接口來獲取它。 –