2013-04-20 2 views
22

Meine Frage ist, was ist der beste Weg, um ein Objekt auf die wartbarste Weise zu einem anderen zuzuordnen. Ich kann die Art und Weise, wie das Dto-Objekt, das wir bekommen, nicht normalisieren soll, ändern, also muss ich eine Möglichkeit schaffen, dies unserer Implementierung ihres Objekts zuzuordnen.Best Practices für die Zuordnung eines Objekts zu einem anderen

Hier ist Beispielcode zu zeigen, was ich passieren müssen:

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

Ich denke, groß, was wäre, wenn ich irgendeine Art von Mapper-Klasse habe, die im Modell Propertyinfo-Objekte nehmen würde, der Typen I möchte ich konvertieren und den "itemname" den ich rausziehen möchte. Hat jemand irgendwelche Vorschläge, um das sauberer zu machen?

Danke!

+0

nicht über die Zuordnung sicher, aber Sie sollten auf jeden Fall bei Generika aussehen und generischen Sammlungen mit: http://csharp-station.com/Tutorial/CSharp/Lesson20 – christiandev

+0

Ich würde ein costructor von Modell vorzuschlagen, die eine nimmt Dto und maps/converts/checks entsprechend hardcoded, da Sie Kompilierungsfehler bekommen, wenn sich etwas in dto ändert. Reflexion und damit der Umgang mit Strings hilft Ihnen nicht, die Wartbarkeit zu erhöhen. – wonko79

Antwort

4

Dies ist eine mögliche generische Implementierung eines wenig Reflexion unter Verwendung von (Pseudo-Code, hat VS nicht jetzt):

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

Verbrauch:

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

Dies wird langsam sein, wenn Sie Erstellen Sie die Mapper-Instanz, aber viel schneller später.

+0

Leider ist die Notwendigkeit hier nicht so geradlinig, wie ich es gerne hätte und die Item-Namen stimmen nicht mit den Namen der Eigenschaften auf dem Modell überein, also glaube ich nicht, dass das funktionieren wird. – Alex

15

Ich würde mich für AutoMapper, eine Open Source und freie Mapping-Bibliothek entscheiden, die es erlaubt, einen Typ in einen anderen zu übertragen, basierend auf Konventionen (dh öffentliche Eigenschaften mit denselben Namen und denselben/abgeleiteten/konvertierbaren Typen zusammen mit vielen anderen abbilden) smart ones).

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

Nicht sicher über Ihre spezifischen Anforderungen, aber AutoMapper unterstützt auch custom value resolvers, die Ihnen helfen, sollte eine einzige, generische Umsetzung Ihrer besonderen Mapper Schreiben: Sehr einfach zu bedienen, werden Sie so etwas wie dies erreichen lassen.

+5

Wir haben Autoapper schon vorher benutzt, aber wir haben es wegen seiner langsamen Performance fallen gelassen. – Alex

+2

Einverstanden. Erledigt das gleiche, endete mit mehr Arbeit, indem er den Auto-Mapper löschte, und schrieb dann eine benutzerdefinierte an erster Stelle. Automapper hat sehr sehr langsame Leistung – ZolaKt

+1

Wir hatten ziemlich das gleiche Problem mit der Leistung, wird es nicht wieder verwenden. –

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

Eine schnelle und schmutzige Art und Weise !! – DKM