2013-04-20 6 views
22

La mia domanda è, qual è il modo migliore in cui posso mappare un oggetto a un altro nel modo più gestibile. Non riesco a cambiare il modo in cui l'oggetto Dto che stiamo ottenendo è impostato per essere più normalizzato, quindi ho bisogno di creare un modo per mappare questo alla nostra implementazione del loro oggetto.Best practice per il mapping di un oggetto a un altro

Ecco esempio di codice per mostrare che cosa ho bisogno per accadere:

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

Penso che ciò che sarebbe bello è che se ho avuto una sorta di classe mapper che avrebbe preso nel modello di oggetti PropertyInfo, il tipo I voglio convertire in, e il "itemname" voglio estrarre. Qualcuno ha qualche suggerimento per rendere questo più pulito?

Grazie!

+0

Non sono sicuro circa la mappatura, ma si dovrebbe assolutamente guardare farmaci generici e l'utilizzo di collezioni generici: http://csharp-station.com/Tutorial/CSharp/Lesson20 – christiandev

+0

Vorrei suggerire un costructor di modello che prende un Dto e mappe/converte/controlla di conseguenza hardcoded quando ottieni errori di compilazione quando qualcosa cambia in dto. La riflessione e quindi la gestione delle stringhe non aiutano a migliorare la manutenibilità. – wonko79

risposta

4

Questa è una possibile implementazione generico utilizzando un po 'di riflessione (pseudo-codice, non hanno VS ora):

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

Usage:

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

Questo sarà lenta quando si crea l'istanza del mapper ma molto più velocemente in seguito.

+0

Sfortunatamente, la necessità qui non è semplice come vorrei e l'elemento Nomi non è necessario correlare ai nomi delle proprietà sul modello, quindi non penso che funzionerà. – Alex

15

Vorrei optare per AutoMapper, una libreria di mapping open source e gratuita che consente di mappare un tipo in un altro, sulla base di convenzioni (ad esempio, mappare le proprietà pubbliche con gli stessi nomi e stessi/derivati ​​/ tipi convertibili, insieme a molte altre smart ones). Molto facile da usare, vi permetterà di raggiungere qualcosa di simile:

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

Non sono sicuro circa le vostre specifiche esigenze, ma supporta anche automapper custom value resolvers, che dovrebbe aiutare a scrivere una sola, generica applicazione della vostra particolare mapper.

+5

Abbiamo usato automapper in precedenza, ma abbiamo avuto un senso a causa del rallentamento delle prestazioni. – Alex

+2

concordato. Fatto la stessa cosa, ha finito con più lavoro lasciando cadere automapper, quindi scrivendo uno personalizzato in primo luogo. Automapper ha prestazioni molto molto lente – ZolaKt

+1

Abbiamo avuto lo stesso problema con le prestazioni, non lo useremo più. –

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

Un modo veloce e sporco !! – DKM

Problemi correlati