2013-04-20 109 views
22

我的問題是,我可以以最易維護的方式將一個對象映射到另一個對象的最佳方式是什麼。我無法改變我們得到的Dto對象被設置爲更規範化的方式,所以我需要創建一種方法將其映射到我們的對象實現。將一個對象映射到另一個對象的最佳實踐

下面是示例代碼來說明我需要發生:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var dto = new Dto(); 

     dto.Items = new object[] { 1.00m, true, "Three" }; 
     dto.ItemsNames = new[] { "One", "Two", "Three" };    

     var model = GetModel(dto); 

     Console.WriteLine("One: {0}", model.One); 
     Console.WriteLine("Two: {0}", model.Two); 
     Console.WriteLine("Three: {0}", model.Three); 
     Console.ReadLine(); 
    } 

    private static Model GetModel(Dto dto) 
    { 
     var result = new Model(); 

     result.One = Convert.ToDecimal(dto.Items[Array.IndexOf(dto.ItemsNames, "One")]); 
     result.Two = Convert.ToBoolean(dto.Items[Array.IndexOf(dto.ItemsNames, "Two")]); 
     result.Three = dto.Items[Array.IndexOf(dto.ItemsNames, "Three")].ToString(); 

     return result; 
    } 
} 

class Dto 
{ 
    public object[] Items { get; set; } 
    public string[] ItemsNames { get; set; } 
} 

class Model 
{ 
    public decimal One { get; set; } 
    public bool Two { get; set; } 
    public string Three { get; set; } 
} 

,我認爲這將是巨大的,如果我有某種映射類的,將採取在模型對象的PropertyInfo,I型想要轉換爲,以及我想要提取的「itemname」。有沒有人有任何建議,使這個更清潔?

謝謝!

+0

不能確定的映射,但你絕對應該看看泛型和使用泛型集合:http://csharp-station.com/Tutorial/CSharp/Lesson20 – christiandev 2013-04-20 08:17:58

+0

我建議型號的costructor,這需要Dto和映射/轉換/檢查相應的硬編碼,因爲當dto中的某些內容發生更改時,您會收到編譯錯誤。反思並因此處理字符串不會幫助您提高可維護性。 – wonko79 2013-04-20 08:24:36

回答

4

這是使用有點反射的可能通用的實現(僞代碼,不具有VS現在):

public class DtoMapper<DtoType> 
{ 
    Dictionary<string,PropertyInfo> properties; 

    public DtoMapper() 
    { 
     // Cache property infos 
     var t = typeof(DtoType); 
     properties = t.GetProperties().ToDictionary(p => p.Name, p => p); 
    } 

    public DtoType Map(Dto dto) 
    { 
     var instance = Activator.CreateInstance(typeOf(DtoType)); 

     foreach(var p in properties) 
     { 
      p.SetProperty(
       instance, 
       Convert.Type(
        p.PropertyType, 
        dto.Items[Array.IndexOf(dto.ItemsNames, p.Name)]); 

      return instance; 
     } 
    } 

用法:

var mapper = new DtoMapper<Model>(); 
var modelInstance = mapper.Map(dto); 

這將是緩慢的,當你創建映射器實例,但稍後更快。

+0

不幸的是,這裏的需求並不像我希望的那樣簡單,項目名稱也不必與模型中屬性的名稱相關聯,所以我認爲這不會起作用。 – Alex 2013-04-22 15:01:16

15

我會選擇AutoMapper,這是一個開放源代碼和免費的映射庫,允許根據約定將一種類型映射到另一種類型(即具有相同名稱和相同/衍生/可轉換類型的映射公共屬性,以及其他許多其他類型smart ones)。使用非常簡單,將讓你實現這樣的事情:

Model model = Mapper.Map<Model>(dto); 

不知道您的具體要求,但AutoMapper還支持custom value resolvers,這將有助於你寫一個單一,通用實現您的特定映射的。

+5

我們之前使用過automapper,但由於性能低下,我們有理由放棄它。 – Alex 2013-04-22 15:02:33

+2

同意。完成同樣的事情後,最終放棄了更多的工作,首先放下automapper然後編寫一個自定義的。 Automapper的性能非常非常慢 – ZolaKt 2015-06-10 12:27:32

+1

我們幾乎有與性能相同的問題,不會再使用它。 – 2018-02-12 04:49:19

1
/// <summary> 
/// map properties 
/// </summary> 
/// <param name="sourceObj"></param> 
/// <param name="targetObj"></param> 
private void MapProp(object sourceObj, object targetObj) 
{ 
    Type T1 = sourceObj.GetType(); 
    Type T2 = targetObj.GetType(); 

    PropertyInfo[] sourceProprties = T1.GetProperties(BindingFlags.Instance | BindingFlags.Public); 
    PropertyInfo[] targetProprties = T2.GetProperties(BindingFlags.Instance | BindingFlags.Public); 

    foreach (var sourceProp in sourceProprties) 
    { 
     object osourceVal = sourceProp.GetValue(sourceObj, null); 
     int entIndex = Array.IndexOf(targetProprties, sourceProp); 
     if (entIndex >= 0) 
     { 
      var targetProp = targetProprties[entIndex]; 
      targetProp.SetValue(targetObj, osourceVal); 
     } 
    } 
} 
+0

一個快速和骯髒的方式! – DKM 2017-06-22 19:37:53

相關問題