Laden...

abstracte Klasse, allgemeinen Konstruktor erzwingen, analog zu Enumerable.Empty<T>()

Erstellt von ill_son vor 3 Jahren Letzter Beitrag vor 3 Jahren 519 Views
I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 3 Jahren
abstracte Klasse, allgemeinen Konstruktor erzwingen, analog zu Enumerable.Empty<T>()

Hallo,

ich habe eine abstracte Klasse wie folgt:


public abstract class EvaluationResult
{
    public bool IsEvaluationValid { get; }
        
    public bool TestPassed { get; }

    public EvaluationResult(bool testPassed, bool isEvaluationValid)
    {
        TestPassed = testPassed;
        IsEvaluationValid = isEvaluationValid;
    }
}

Von dieser leite ich andere Result-Klassen ab, die neben den beiden Properies noch andere haben, in denen irgendwelche Erbebniswerte stehen.

Nun möchte ich für den Fall, dass keine Bewertung durchgeführt werden konnte, weil beispielsweise die Eingabeparameter der Bewertungsfunktion nicht sinnvoll sind, eine abgeleitete Klasse mit


IsEvaluationValid = false 

zurück geben und dazu eine ensprechende statische Methode


DerivedResult.Invalid()

haben, vergleichbar mit Enumerable.Empty<T>(), nur das T nur eine Subklasse von EvaluationREsult sein darf. Wie stelle ich das an?

Grüße, Alex

Final no hay nada más

4.931 Beiträge seit 2008
vor 3 Jahren

Enumerable.Empty<T>() ist kein Konstruktor, sondern eine statische Methode.

Und im Source-Code von Enumerable.Empty sieht man, daß dort eine Instanz (leeres Array) gekapselt in einer eigenen Klasse (EmptyEnumerable<TElement>) zurückgegeben wird.

Brauchst du denn wirklich für deinen Fall eine generische Methode (bzw. Instanz)?
M.E. reicht bei dir einfach, daß du von EvaluationResult eine Klasse EmptyResult ableitest und davon dann ein (statisches) Objekt zurückgibst.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 3 Jahren

Hallo Th69,

danke für deine Antwort. Das mit dem Kontruktor war etwa unglücklich ausgedrückt. Die Implementierung von Enumerable.Empty hatte ich mir angeschaut.

Ich habe verschiedene Bewertungsmethoden, die verschiedene Ergebnisse zurückgeben. Deshalb ist das mit der einen invaliden Klasse bisschen schwierig. Ich hab es jetzt erst mal so gelöst, dass ich für jede Result-Klasse eine statische Methode in einer statischen Klasse habe, die mir das gewünschte Objekt liefert. st nicht optimal, aber für meinen Fall passt das so.

Final no hay nada más

2.078 Beiträge seit 2012
vor 3 Jahren

Ich hab es jetzt erst mal so gelöst, dass ich für jede Result-Klasse eine statische Methode in einer statischen Klasse habe

Eine andere Möglichkeit hast Du auch nicht, sowas wie ein statisches Interface gibt es nicht.

Du müsstest also ganz umdenken, z.B. indem Du eine Factory erstellst, die die ein gültiges und ein ungültiges Objekt bauen kann. Die musst Du dann natürlich für jede deiner Klassen implementieren.
Oder Du verwendest Reflection (also ActivatorUtilities.CreateInstance), was ich persönlich aber für sehr ungünstig halte, da Du dann eine "heimliche Übereinkunft" hast, welche Parameter jede Klasse haben darf.

16.807 Beiträge seit 2008
vor 3 Jahren

Ich verstehe ehrlich gesagt die Klasse nicht. Was soll sie denn ausdrücken?
Kann sie valide sein, wenn ein Test niemals erfolgreich war?

Wenns logisch eindeutige Zustände sind, dann würde ich viel eher ein Enum verwenden.

2.078 Beiträge seit 2012
vor 3 Jahren

Mich erinnert das ein bisschen an ValidationResult.
Das Ding soll ja sowohl einen gültigen als auch einen ungültigen Zustand darstellen können.
Und hier kommen scheinbar mehrere Ableitungen mit Daten je Zustand, die alle ein ähnliches Verhalten zeigen sollen.

Allerdings - wäre es dann nicht klüger, den Zustand (Valide vs. Invalide) von den Daten zu trennen?
Wie Abt schon sagt, ein Enum oder ein Bool und daneben dann die restlichen Daten - zumindest soweit sie gefüllt werden können oder null.

Z.B. heute erst hab ich bei einer Web-API von diesem Vorgehen profitiert:
Es gibt viele verschiedene Responses, die Daten sehen völlig anders aus, aber ich konnte mich immer darauf verlassen, dass es einen Status und eine Meldung dazu gibt, immer an der selben Stelle.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 3 Jahren

Hallo Abt,

Beispielsweise verrechne ich in der Bewertung zwei Messsignale miteinander. Wenn diese sich aber gar nicht zeitlich überlappen, weil der Benutzer die falschen Daten ausgewählt hat, dann kann ich kein valides Ergebnis erzeugen. Ansonsten kann es sein, dass das Ergebnis berechnet, aber der Test nicht bestanden wurde. Dann wäre das Ergebnis valide, aber negativ. Ich bin da für Vorschlage sehr offen, wenn du das anders/besser lösen würdest.

Edit: @Palladin: Meinst du eine Art TryEvaluate-Methode mit out-Parameter, wie das beim numerischen Parsen von strings verwendet wird?

Grüße, Alex

Final no hay nada más

16.807 Beiträge seit 2008
vor 3 Jahren

ill_son, mit Deiner Erklärung macht das nun etwas mehr Sinn und erinnert tatsächlich etwas an ValidationResult.
Da kannst Du dann - wie Palladin sagt wirklich einfach mit statischen Methoden arbeiten, was ein legitimer Zweck ist und durchaus üblich.

Bekannt ist das Verhalten auch vom ModelBinder, zB ModelBinderResult.Success().
Das Nutzen eines struct ist hier durchaus sinnvoll.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 3 Jahren

Danke nochmal.

Final no hay nada más