C# - Generika-basierten Objekt-zu-Objekt-mapper Frage
Habe ich die Notwendigkeit einer Objekt-zu-Objekt-mapper in meiner Anwendung. Ich habe versucht ein paar, aber nicht in der Lage, etwas zu finden, das passt zu meinen Bedürfnissen, also Schreibe ich meine eigenen. Derzeit habe ich eine Schnittstelle wie unten:
public interface IMapper<T, R> {
T Map(R obj);
}
Ich dann implementieren eine AccountMapper, dass die Karten ein Kunde auf ein Konto wie:
public class AccountMapper : IMapper<Account, Customer> {
Account Map(Customer obj) {
//mapping code
}
}
Dieser funktioniert so weit, aber ich habe mehrere Quell-Entitäten, die Karte, um die gleiche Ziel-Entität. Zum Beispiel habe ich eine Zahlung und eine Rechnung, dass beide anzeigen zu BillHistory. Für die oben genannten, um diese Unterstützung, die ich brauche, um zwei separate Mappern (zB. BillHistoryPaymentMapper und BillHistoryInvoiceMapper), was in Ordnung ist. Allerdings, ich würde lieben im Stande zu sein es zu implementieren, etwas anders wie unten. Problem ist nur ich weiß nicht, ob es möglich ist und wenn ja, weiß ich nicht die korrekte syntax.
public interface IMapper<T> {
T Map<R>(R obj);
}
public class BillHistoryMapper : IMapper<Account> {
public BillHistory Map<Invoice>(Invoice obj) {
//mapping code
}
public BillHistory Map<Payment>(Payment obj) {
//mapping code
}
}
Während der ersten Umsetzung funktioniert gut, die zweite wäre etwas eleganter. Ist das möglich und wenn ja, was wäre die richtige syntax Aussehen?
Bearbeiten-------
Ich hasse es, wenn Menschen dies tun, aber natürlich habe ich vergessen zu erwähnen, ein kleines detail. Wir haben eine abstrakte Klasse, die zwischen dem mapper und die Schnittstelle zu implementieren, die einige gemeinsame Logik für alle Mapper. Also mein mapper Signatur ist eigentlich:
public class BillHistoryMapper : Mapper<BillHistory, Invoice> {
}
wo Mapper enthält:
public abstract class Mapper<T, R> : IMapper<T, R> {
public IList<T> Map(IList<R> objList) {
return objList.ToList<R>().ConvertAll<T>(new Converter<T, R>(Map));
}
}
Du musst angemeldet sein, um einen Kommentar abzugeben.
Müssen Sie Ihre erste Schnittstelle und die Schnittstelle implementieren, mehrere Male auf das Objekt:
Ich würde ernsthaft erwägen Sie einen Blick auf AutoMapper statt zu schreiben Ihre eigenen. Es gibt eine Menge von Nuancen in der Zuordnung, dass es bereits gelöst, nicht zu erwähnen, es wurde durch zahlreiche performance-Tests, bug-fixes, etc.
Hinblick auf Ihre abstrakte Klasse erwägen, entfernen Sie es und ersetzen Sie es mit einer extension-Methode. Dies ermöglicht Ihnen die Nutzung der
MapAll
Funktion, unabhängig davon, ob Sie die Schnittstelle implementieren, oder verwenden Sie eine Art von Vererbung Kette.Dieser wird nun machen es einfacher, wenn Sie versuchen, Ihr problem zu lösen über, da Sie nicht mehr zu Erben von einer Basisklasse können Sie nun die Umsetzung der mapping-Schnittstelle für die Typen, die Sie zuordnen möchten.
Auch in Erwägung ziehen, Ihren
IMapper
generischen Parameter, die für den anderen Weg (ich nahm mir die Freiheit in den vorherigen Beispielen):Der Grund dafür ist, dass es direkt Karten für die
System.Konverter<T>
delegieren und Sie können etwas tun:AutoMapper wurde auch vorgeschlagen, die Ihr Leben einfacher machen wird. Allerdings, wenn Sie wollen, um halten Sie Ihre mapping Abstraktion und haben Ihren code Agnostiker zu Ihren mapping-Strategie, dann ist es sehr einfach, um die obige Schnittstelle zu Spritzen, ein wrapper um AutoMapper. Es wird auch bedeuten Sie können weiterhin verwenden, die
MapAll
extension-Methode (siehe oben).Letzte Wort
Halten Sie auch im Verstand, den Sie sind nicht immer zu finden, die zu Ihren mapping-Strategie wird die Arbeit auf dem Brett, so versuchen Sie nicht zu kämpfen Ihre domain und Kraft, um fit in Ihrer mapping-Strategie. Ein besonderes Beispiel ist Sie haben könnten, um anzeigen von zwei input-Elemente in einem. Sie können offensichtlich machen diese passen Ihre Strategie aber Sie können finden, wird es chaotisch. In diesem bestimmten Beispiel betrachten Sie es als eine Zusammenführen.
Ihrem zweiten Beispiel wird die Arbeit mit nur ein paar änderungen:
Ich bin mir nicht sicher, ob dies tatsächlich gewinnt Sie nichts über das vorhandene Muster.
Wenn es nur eine begrenzte Anzahl von Typen, die Sie zuordnen möchten, aus, dann würde ich die erste Methode verwenden, deklarieren Sie die input-und output-Arten in der interface-definition. Dann ein mapper können Schnittstellen implementieren, die für jede Eingabe, geben Sie Sie unterstützt, so Ihre
BillHistoryMapper
würde deklariert werden als: