Ich habe ein großes Objekt:
class BigObject{
public int Id {get;set;}
public string FieldA {get;set;}
// ...
public string FieldZ {get;set;}
}
und ein spezialisiertes, DTO-ähnliches Objekt:
class SmallObject{
public int Id {get;set;}
public EnumType Type {get;set;}
public string FieldC {get;set;}
public string FieldN {get;set;}
}
Ich persönlich finde ein Konzept zum expliziten Umwandeln von BigObject in SmallObject - in dem Wissen, dass es sich um eine Einwegoperation handelt, bei der Daten verloren gehen - sehr intuitiv und lesbar:
var small = (SmallObject) bigOne;
passSmallObjectToSomeone(small);
Es wird mit dem expliziten Operator implementiert:
public static explicit operator SmallObject(BigObject big){
return new SmallObject{
Id = big.Id,
FieldC = big.FieldC,
FieldN = big.FieldN,
EnumType = MyEnum.BigObjectSpecific
};
}
Jetzt könnte ich eine SmallObjectFactory
Klasse mit einer FromBigObject(BigObject big)
Methode erstellen , die dasselbe macht, sie zur Abhängigkeitsinjektion hinzufügt und sie bei Bedarf aufruft ... aber für mich scheint es noch komplizierter und unnötiger zu sein.
PS: Ich bin mir nicht sicher, ob dies relevant ist, aber es wird möglich sein OtherBigObject
, das auch in eine SmallObject
andere Einstellung umzuwandeln EnumType
.
quelle
.ToSmallObject()
Methode (oderGetSmallObject()
). Ein kurzer Moment der Vernunft - Ich wusste, dass etwas mit meinem Denken nicht stimmt, also habe ich euch gefragt :)ToSmallObject
Methode.Antworten:
Keine der anderen Antworten hat meiner bescheidenen Meinung nach Recht. In dieser Stackoverflow-Frage argumentiert die am höchsten bewertete Antwort, dass der Zuordnungscode nicht in die Domäne aufgenommen werden soll. Um Ihre Frage zu beantworten, nein - Ihre Verwendung des Cast-Operators ist nicht besonders gut. Ich würde empfehlen, einen Zuordnungsdienst zu erstellen, der zwischen Ihrem DTO und Ihrem Domänenobjekt liegt, oder Sie könnten dafür Automapper verwenden.
quelle
Es ist ... nicht großartig. Ich habe mit Code gearbeitet, der diesen cleveren Trick ausgeführt hat und zu Verwirrung geführt hat. Schließlich würden Sie erwarten, dass Sie das einfach
BigObject
in eineSmallObject
Variable umwandeln können, wenn die Objekte so miteinander verknüpft sind, dass sie umgewandelt werden können. Es funktioniert jedoch nicht - Sie erhalten Compiler-Fehler, wenn Sie es versuchen, da sie, was das Typsystem betrifft, nichts miteinander zu tun haben. Es ist für den Gießer auch leicht unangenehm, neue Objekte herzustellen.Ich würde stattdessen eine
.ToSmallObject()
Methode empfehlen . Es ist klarer darüber, was tatsächlich vor sich geht und wie ausführlich.quelle
mildly distasteful
ist eine Untertreibung. Es ist bedauerlich, dass die Sprache zulässt, dass so etwas wie eine Typografie aussieht. Niemand würde vermuten, dass es sich um eine tatsächliche Objekttransformation handelt, wenn sie es nicht selbst geschrieben hätten. In einem Ein-Personen-Team, okay. Wenn Sie mit jemandem zusammenarbeiten, ist dies im besten Fall eine Zeitverschwendung, da Sie anhalten und herausfinden müssen, ob es sich wirklich um eine Besetzung handelt oder um eine dieser verrückten Transformationen..ToSmallObject()
. Sie sollten Operatoren kaum überschreiben.Get
dass ein vorhandenes Objekt zurückgegeben wird. Wenn Sie die Operationen für das kleine Objekt nicht überschrieben haben, würden zweiGet
Aufrufe ungleiche Objekte zurückgeben, was zu Verwirrung / Fehlern / wtfs führen würde.Ich kann zwar nachvollziehen, warum Sie eine benötigen, aber
SmallObject
ich würde das Problem anders angehen. Mein Ansatz für diese Art von Problem ist die Verwendung einer Fassade . Ihr einziger Zweck istBigObject
es, bestimmte Mitglieder zusammenzufassen und nur zur Verfügung zu stellen. Auf diese Weise handelt es sich um eine neue Schnittstelle in derselben Instanz und nicht um eine Kopie. Natürlich möchten Sie vielleicht auch eine Kopie erstellen, aber ich würde Ihnen empfehlen, dies mithilfe einer Methode zu tun, die zu diesem Zweck (zum Beispielreturn new SmallObject(instance.Clone())
) in Kombination mit der Fassade erstellt wurde .Facade bietet eine Reihe weiterer Vorteile: Es muss sichergestellt werden, dass bestimmte Abschnitte Ihres Programms nur die Mitglieder verwenden können, die über Ihre Fassade verfügbar sind, und dass das, was Sie nicht wissen sollten, nicht genutzt werden kann. Darüber hinaus bietet es den enormen Vorteil, dass Sie
BigObject
bei zukünftigen Wartungsarbeiten flexibler vorgehen können, ohne sich über die Verwendung im gesamten Programm Gedanken machen zu müssen. Solange Sie das alte Verhalten in irgendeiner Form emulieren können, können Sie dieSmallObject
Arbeit so machen, wie sie vorher war, ohne dass Sie Ihr Programm überall ändernBigObject
müssten.Beachten Sie, dass
BigObject
dies nicht davon abhängt,SmallObject
sondern umgekehrt (wie es meiner bescheidenen Meinung nach sein sollte).quelle
SmallObject
beiSmallObject
oder liegtBigObject
. Dieser Ansatz erzwingt standardmäßigSmallObject
die Vermeidung von Abhängigkeiten von privaten / geschützten Mitgliedern vonBigObject
. Wir können einen Schritt weiter gehen und Abhängigkeiten von privaten / geschützten Mitgliedern vermeiden,SmallObject
indem wir eineToSmallObject
Erweiterungsmethode verwenden.BigObject
. Wenn Sie etwas Ähnliches tun wollten, würden Sie dafür bürgen, eineToAnotherObject
Erweiterungsmethode innerhalb von zu erstellenBigObject
? Dies sollte nicht die Sorge sein,BigObject
da es vermutlich bereits groß genug ist, wie es ist. Sie können sich auchBigObject
von der Erstellung der Abhängigkeiten trennen , dh Sie können Fabriken und dergleichen verwenden. Der andere Ansatz ist stark paartBigObject
undSmallObject
. Das mag in diesem speziellen Fall in Ordnung sein, aber meiner bescheidenen Meinung nach ist es keine bewährte Vorgehensweise.BigObject
Kopplung mehrSmallObject
, es ist nur eine statische Methode, die ein Argument von annimmtBigObject
und zurückgibtSmallObject
. Erweiterungsmethoden sind eigentlich nur syntaktischer Zucker, um statische Methoden besser aufzurufen. Die Erweiterungsmethode ist nicht Teil vonBigObject
, sondern eine völlig separate statische Methode. Es ist eigentlich eine ziemlich gute Anwendung von Erweiterungsmethoden und insbesondere für DTO-Konvertierungen sehr praktisch.Es gibt eine sehr starke Konvention, die besagt, dass veränderbare Referenztypen identitätserhaltend sind. Da das System in Situationen, in denen ein Objekt des Quelltyps einer Referenz des Zieltyps zugewiesen werden könnte, im Allgemeinen keine benutzerdefinierten Umwandlungsoperationen zulässt, gibt es nur wenige Fälle, in denen benutzerdefinierte Umwandlungsoperationen für eine veränderbare Referenz sinnvoll wären Typen.
Ich würde als Voraussetzung vorschlagen, dass, wenn beide Darstellungen auf dasselbe Objekt angewendet werden, sie einige Zeit
x=(SomeType)foo;
später gegeben werdeny=(SomeType)foo;
, siex.Equals(y)
immer und für immer zutreffen sollten, auch wenn das betreffende Objekt zwischen den beiden Darstellungen geändert wurde. Eine solche Situation könnte eintreten, wenn z. B. eines ein Paar von Objekten unterschiedlichen Typs hätte, von denen jedes einen unveränderlichen Verweis auf das andere enthielt, und das Umsetzen eines Objekts auf den anderen Typ seine gepaarte Instanz zurückgeben würde. Dies kann auch für Typen gelten, die als Wrapper für veränderbare Objekte dienen, vorausgesetzt, die Identitäten der zu umhüllenden Objekte sind unveränderlich, und zwei Wrapper desselben Typs melden sich als gleich, wenn sie dieselbe Auflistung umhüllen.Ihr spezielles Beispiel verwendet veränderbare Klassen, behält jedoch keine Form der Identität bei. Als solches würde ich vorschlagen, dass es keine angemessene Verwendung eines Casting-Operators ist.
quelle
Es könnte in Ordnung sein.
Ein Problem mit Ihrem Beispiel ist, dass Sie solche beispielhaften Namen verwenden. Erwägen:
Wenn Sie eine gute Vorstellung davon haben, was ein Long und Int bedeutet, sind sowohl die implizite Umwandlung von
int
inlong
als auch die explizite Umwandlung vonlong
inint
durchaus verständlich. Es ist auch verständlich , wie3
wird3
und ist nur ein weiterer Weg zur Arbeit mit3
. Es ist verständlich, wie diesint.MaxValue + 1
in einem überprüften Kontext fehlschlagen wird . Sogar wie esint.MaxValue + 1
in einem ungeprüften Kontext funktionieren wird,int.MinValue
ist nicht die schwierigste Sache, die es gibt.Wenn Sie implizit in einen Basistyp oder explizit in einen abgeleiteten Typ umwandeln, ist dies für jeden verständlich, der weiß, wie die Vererbung funktioniert, was geschieht und was das Ergebnis sein wird (oder wie es fehlschlagen könnte).
Bei BigObject und SmallObject habe ich keine Ahnung, wie diese Beziehung funktioniert. Wenn Ihre realen Typen so beschaffen sind, dass die Casting-Beziehung offensichtlich ist, dann ist Casting in der Tat eine gute Idee, auch wenn dies häufig der Fall ist normales vererbungsbasiertes Casting wird ausreichen.
quelle
BigObject
eine beschreibenEmployee {Name, Vacation Days, Bank details, Access to different building floors etc.}
undSmallObject
eine seinMoneyTransferRecepient {Name, Bank details}
. Es gibt eine einfache Übersetzung vonEmployee
nachMoneyTransferRecepient
, und es gibt keinen Grund, mehr Daten als erforderlich an die Bankenanwendung zu senden.