C# verwendet generische Typen, um einen teilweise geladenen Datenbaum darzustellenC#

Ein Treffpunkt für C#-Programmierer
Anonymous
 C# verwendet generische Typen, um einen teilweise geladenen Datenbaum darzustellen

Post by Anonymous »

Das Problem, das ich zu lösen versuche, besteht darin, einen teilweise geladenen Baum von Objekten mithilfe von C#-Generika darzustellen. Angenommen, wir haben die folgenden Klassen:

Code: Select all

public class Address
{
public string Line1 { get; set; }
public string City { get; set; }
}

public class Customer
{
public string Name { get; set; }
public Address Address { get; set; }
public ICollection Orders { get; set; }
}

public class Order
{
public int OrderNumber { get;  set; }
public ICollection[*] Lines { get; set; }
}

public class Line
{
public int Qty { get; set; }
public string Product { get; set; }
}
Die Klassen haben Verweise aufeinander, aber manchmal werden diese Verweise nicht geladen und die Felder sind stattdessen einfach null. Das Ändern dieser Eigenschaften in nullfähige Eigenschaften führt zu eigenen Problemen, da die Eigenschaften immer auf Null überprüft werden müssen, obwohl wir zur Kompilierungszeit wissen, welche Eigenschaften geladen werden und welche nicht.
Meine Lösung besteht aus einer Reihe von Wrapper-Typen, die automatisch generiert werden können. Für den Kunden erstellen wir beispielsweise die folgenden Schnittstellen:

Code: Select all

public interface NoCustomer { }

public interface ICustomer :  NoCustomer
where TAddr : NoAddress
where TOrders : NoOrder
{
string Name { get; set; }
}
So bedeutet beispielsweise ICustomer einen Kunden, bei dem die Adresse und die Bestellungen nicht geladen werden, ICustomer jedoch einen Kunden, bei dem die Adresse und die Bestellungen geladen werden, die Zeilen der Bestellungen jedoch nicht. Wir können Erweiterungsmethoden verwenden, um sicherzustellen, dass Sie zur Kompilierungszeit nicht versuchen, auf eines dieser entladenen Objekte zuzugreifen:

Code: Select all

public static class CustomerExtensions
{
public static IAddress Address(this ICustomer customer)
where TOrders : NoOrder
{
...
}
}
Da die Typen kovariant sind, können wir Funktionen schreiben, die einen Customer annehmen und ihm einen Customer übergeben, oder im Allgemeinen ein „stärker geladenes“ Objekt verwenden, wenn nur ein „weniger geladenes“ Objekt benötigt wird.
Das ist alles schön und gut, aber das Problem entsteht, wenn ich versuche, die Verwendung der Typen ergonomischer zu gestalten. Standardmäßig beginnen die Typen ziemlich ausführlich zu werden, und schlimmer noch, Sie verbringen viele Zeichen damit, über Typen zu reden, die noch nicht einmal geladen sind. Zum Beispiel:

Code: Select all

ICustomer
Es ist nervig zu schreiben, und ich würde lieber schreiben

Code: Select all

ICustomer
oder etwas Ähnliches stattdessen. Letzteres ist viel klarer, da nur die Namen der geladenen Typen (Kunde und Bestellung) angezeigt werden.
Ich habe jedoch Schwierigkeiten, herauszufinden, wie das funktioniert.
  • Mein erster Ansatz besteht einfach darin, die Schnittstellen „NoCustomer“, „NoAddress“ usw. durch eine einzige Schnittstelle „No“ zu ersetzen. Das Problem ist, dass jetzt alle Schnittstellentypen vom Typ No erben, sodass Sie falsche Typargumente angeben können und der Compiler nichts dagegen tun kann (z. B. würde ICustomer gut kompilieren!).
  • Mein zweiter Ansatz besteht darin, zu versuchen, sowohl NoCustomer-Typen als auch auch einen generischen No-Typ zu haben, der von allen erbt sie. Wir könnten also ICustomer oder alternativ ICustomer schreiben, aber nicht ICustomer. Oberflächlich betrachtet scheint es, als würde es funktionieren, aber das Problem ist, dass ICustomer von ICustomer

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post