Wie soll ich mit einer Situation umgehen, in der ich mehrere unabhängige Typen speichern muss, aber bestimmte Typen bei Bedarf bereitstellen muss?

StackOverflow https://stackoverflow.com/questions/54219

  •  09-06-2019
  •  | 
  •  

Frage

Ich arbeite an einem Editor für Dateien, die von einem wichtigen internen Testtool verwendet werden, das wir verwenden.Das Tool selbst ist groß, kompliziert und das Refactoring oder Neuschreiben würde mehr Ressourcen erfordern, als wir auf absehbare Zeit dafür aufwenden können. Daher sind mir bei großen Änderungen die Hände gebunden.Ich muss eine .NET-Sprache verwenden.

Bei den Dateien handelt es sich um XML-serialisierte Versionen von vier Klassen, die vom Tool verwendet werden (nennen wir sie A, B, C und D).Wenn alles in Ordnung ist, bilden die Klassen eine Baumstruktur.Unser Editor lädt eine Reihe von Dateien, deserialisiert sie, ermittelt die Beziehungen zwischen ihnen und verfolgt alle fehlerhaften Zustände, die er finden kann.Die Idee besteht darin, dass wir von der manuellen Bearbeitung dieser Dateien wegkommen, die zu einer Menge Fehler führt.

Für einen bestimmten Fehlertyp möchte ich eine Sammlung aller Dateien verwalten, bei denen das Problem auftritt.Das Problem kann bei allen vier Klassen auftreten, und ich möchte die Codeduplizierung so weit wie möglich reduzieren.Eine wichtige Anforderung besteht darin, dass der Benutzer in der Lage sein muss, die Artikel in Sets zu erhalten.Sie müssen beispielsweise alle A-Objekte mit einem Fehler abrufen, und ihnen zu sagen, sie sollen die gesamte Sammlung durchlaufen und auswählen, was sie wollen, ist im Vergleich zu a inakzeptabel GetAs() Methode.Mein erster Gedanke war also, ein generisches Element zu erstellen, das das deserialisierte Objekt und einige Metadaten in Beziehung setzt, um den Fehler anzuzeigen:

public class ErrorItem<T>
{
    public T Item { get; set; }
    public Metadata Metadata { get; set; }
}

Dann hätte ich eine Sammlungsklasse, die alle Fehlerelemente enthalten könnte, mit Hilfsmethoden, um die Elemente einer bestimmten Klasse zu extrahieren, wenn der Benutzer sie benötigt.Hier beginnt das Problem.

Keine der Klassen erbt von einem gemeinsamen Vorfahren (außer Object).Dies war wahrscheinlich ein Fehler des ursprünglichen Entwurfs, aber ich habe ein paar Tage darüber nachgedacht, und die Klassen haben wirklich nicht viel gemeinsam, außer einer GUID-Eigenschaft, die jedes Element eindeutig identifiziert, sodass ich verstehen kann, warum der ursprüngliche Designer hat sie nicht durch Erbschaft verbunden.Dies bedeutet, dass die einheitliche Fehlersammlung gespeichert werden müsste ErrorItem<Object> Objekte, da ich keine Basisklasse oder Schnittstelle habe, um einzuschränken, was hereinkommt.Allerdings erscheint mir die Idee dieser einheitlichen Sammlung dadurch etwas fragwürdig:

Public Class ErrorCollection
{
    public ErrorItem<Object> AllItems { get; set; }
}

Dies hat jedoch Auswirkungen auf die öffentliche Schnittstelle.Was ich wirklich möchte, ist, das Richtige zurückzugeben ErrorItem generischen Typ wie diesen:

public ErrorItem<A>[] GetA()

Das ist unmöglich, weil ich nur speichern kann ErrorItem<Object>!Ich habe in meinem Kopf einige Problemumgehungen durchgegangen;Meistens beinhalten sie die Erstellung eines neuen ErrorItem des entsprechenden Typs im Handumdrehen, aber es fühlt sich einfach irgendwie hässlich an.Ein anderer Gedanke war die Verwendung von a Dictionary Elemente nach Typ sortiert zu halten, aber es scheint immer noch nicht richtig zu sein.

Gibt es ein Muster, das mir hier helfen könnte?Ich weiß, dass der einfachste Weg, dieses Problem zu lösen, darin besteht, eine Basisklasse hinzuzufügen, von der A, B, C und D abgeleitet sind, aber ich versuche, so wenig Einfluss wie möglich auf das ursprüngliche Tool zu haben.Sind die Kosten einer Problemumgehung so hoch, dass ich auf einen Wechsel des ursprünglichen Tools drängen sollte?

War es hilfreich?

Lösung

Wenn A, B, C und D haben nichts gemein dann das Hinzufügen einer Basisklasse nicht wirklich Sie etwas bekommen. Es wird nur eine leere Klasse sein und in der Tat ist die gleiche wie Objekt sein.

Ich hatte gerade eine ErrorItem Klasse ohne die Generika schaffen, Item ein Objekt machen und einige Casting tun, wenn Sie die Objekte verwenden möchten, verwiesen. Wenn Sie eine der Eigenschaften oder Methoden der A, B, C oder D-Klasse anders als die Guid verwenden möchten, würden Sie hatte sie trotzdem werfen.

Andere Tipps

Ist das, was Sie suchen?

private List<ErrorItem<object>> _allObjects = new List<ErrorItem<object>>();

public IEnumerable<ErrorItem<A>> ItemsOfA
{
    get
    {
        foreach (ErrorItem<object> obj in _allObjects)
        {
            if (obj.Item is A)
                yield return new ErrorItem<A>((A)obj.Item, obj.MetaData);
        }
    }
}

Wenn Sie die ItemsOfA zwischenzuspeichern können Sie ganz einfach tun:

private List<ErrorItem<A>> _itemsOfA = null;

public IEnumerable<ErrorItem<A>> ItemsOfACached
{
    if (_itemsOfA == null)
        _itemsOfA = new List<ErrorItem<A>>(ItemsOfA);
    return _itemsOfA;
}

Die Antwort, die ich mit so weit zu gehen habe, ist eine Kombination aus den Antworten von fryguybob und Mendelt Siebenga.

eine Basisklasse Hinzufügen würde nur den Namensraum verschmutzen und ein ähnliches Problem einzuführen, wie Mendelt Siebenga hingewiesen. Ich würde mehr Kontrolle bekommen über welche Gegenstände in die Sammlung gehen, aber ich würde müssen noch ErrorItem<BaseClass> speichern und noch einige Castings tun, also würde ich ein etwas anderes Problem mit derselben Ursache habe. Aus diesem Grunde ich den Posten als Antwort ausgewählt. Es weist darauf hin, dass ich einige Würfe, egal haben werde zu tun, was und KISS diktieren würde, dass die zusätzliche Basisklasse und Generika sind zu viel

Ich mag fryguybob das nicht für die Lösung Antwort selbst, sondern ich über yield return für die Erinnerung, die eine nicht-Cache-Version einfacher machen zu schreiben (ich wollte LINQ verwenden). Ich denke, eine Cache-Version ein wenig klug ist, wenn die erwarteten Leistungsparameter nicht die Nicht-Cache-Version noticably langsamer machen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top