Wirft eine Ausnahme von einer Eigenschaft eine schlechte Form?

14

Ich war schon immer der Meinung, dass Eigenschaften (dh ihre set / get-Operationen) schnell / sofort und fehlerfrei sein sollten. Sie sollten niemals versuchen / herumschnüffeln müssen, um eine Immobilie zu bekommen oder einzustellen.

Ich suche jedoch nach Möglichkeiten, rollenbasierte Sicherheit auf die Eigenschaften einiger Objekte anzuwenden. Zum Beispiel eine Employee.Salary-Eigenschaft. Einige der Lösungen , die ich über die anderen laufen habe versucht haben (ein insbesondere ist das AOP Beispiel hier ) beinhaltet eine Ausnahme auszulösen , wenn die Accessor nicht die richtigen Berechtigungen haben - aber das geht gegen eine persönliche Regel , dass ich je hatte schon lange.

Also frage ich: irre ich mich? Haben sich die Dinge geändert? Wurde akzeptiert, dass Eigenschaften Ausnahmen auslösen können sollten?

Steven Evers
quelle
1
Die gleiche Frage auf Stackoverflow hat mehr Aufmerksamkeit und so bessere Antworten.
Roman Starkov

Antworten:

14

Wenn Sie den Wert einer Eigenschaft festlegen, ist es in Ordnung, eine Ausnahme für einen ungültigen Wert auszulösen

Das Abrufen des Werts einer Eigenschaft sollte (fast) nie eine Ausnahme auslösen

Verwenden Sie für den rollenbasierten Zugriff unterschiedliche / unauffällige Schnittstellen oder Fassaden. Lass die Leute nicht Dinge sehen, die sie nicht haben können!

Steven A. Lowe
quelle
5

Ich halte es meistens für eine schlechte Form, aber selbst Microsoft empfiehlt, manchmal Ausnahmen zu verwenden. Ein gutes Beispiel ist die abstrakte Eigenschaft Stream.Length . Nach den Richtlinien würde es mir mehr darum gehen, Nebenwirkungen auf Getter zu vermeiden und Nebenwirkungen auf Setter zu begrenzen.

ChaosPandion
quelle
4

Ich würde definitiv argumentieren, dass es einen Fehler im Design gibt, wenn Sie das Gefühl haben, Ausnahmen von einem Property Setter oder Getter auszulösen.

Eine Eigenschaft ist eine Abstraktion, die nur einen Wert darstellt . Und Sie sollten in der Lage sein, einen Wert festzulegen, ohne befürchten zu müssen, dass dies eine Ausnahme auslösen könnte. *

Wenn das Setzen der Eigenschaft zu einem Nebeneffekt führt, sollte dieser eigentlich als Methode implementiert werden. Und wenn es keine Nebenwirkungen erzeugt, sollte keine Ausnahme geworfen werden.

Ein Beispiel, das bereits in einer anderen Antwort erwähnt wurde, ist die Stream.PositionEigenschaft. Dies führt zu Nebenwirkungen und kann Ausnahmen auslösen. Aber dieser Property-Setter ist im Grunde nur ein Wrapper Stream.Seek, den Sie stattdessen aufrufen können.

Persönlich glaube ich, dass die Position keine beschreibbare Eigenschaft sein sollte.

Ein weiteres Beispiel, bei dem Sie versucht sein könnten, eine Ausnahme von einem Eigenschaftssetzer auszulösen, ist die Validierung von Daten:

public class User {
    public string Email {
        get { return _email; }
        set { 
            if (!IsValidEmail(value)) throw InvalidEmailException(value);
            _email = value;
        }
    }

Aber es gibt eine bessere Lösung für dieses Problem. Geben Sie einen Typ ein, der eine gültige E-Mail-Adresse darstellt:

public class Email {
    public Email(string value) {
        if (!IsValidEmail(value)) throw new InvalidEmailException(value);
        ...
    }
    ...
}

public class User {
    public Email Email { get; set; }
}

Das Email Klasse stellt sicher, dass kein Wert gespeichert werden kann, der keine gültige E-Mail-Adresse ist, und Klassen, die E-Mails speichern müssen, müssen diese nicht mehr überprüfen.

Dies führt auch zu einer höheren Kohäsion (ein Indikator für gutes Softwaredesign) - das Wissen darüber, was eine E - Mail - Adresse ist und wie sie validiert wird, existiert nur in der Email Klasse, die nur dieses Problem hat.

* ObjectDisposedException ist die einzige gültige Ausnahme (kein Wortspiel beabsichtigt), die mir derzeit einfällt.

Pete
quelle
2

Ich weiß, dass Ihre Frage .NET-spezifisch ist , aber da C # eine gewisse Geschichte mit Java teilt, dachte ich, dass Sie vielleicht interessiert sind. Ich bin nicht in irgendeiner Weise impliziert , dass da etwas in Java getan wird, sollte es in C # erfolgen. Ich weiß, dass die beiden sehr unterschiedlich sind, insbesondere, wie C # die Unterstützung von Eigenschaften auf Sprachebene stark verbessert hat. Ich gebe nur einen Kontext und eine Perspektive.

Aus der JavaBeans-Spezifikation :

Eingeschränkte Eigenschaften Manchmal, wenn eine Eigenschaftsänderung auftritt, möchte eine andere Bean die Änderung möglicherweise validieren und ablehnen, wenn sie unangemessen ist. Wir bezeichnen Eigenschaften, die dieser Art der Prüfung unterzogen werden, als eingeschränkte Eigenschaften. In Java Beans sind Methoden zum Festlegen von eingeschränkten Eigenschaften erforderlich, um die PropertyVetoException zu unterstützen. Dies dokumentiert den Benutzern der eingeschränkten Eigenschaft, dass versuchten Aktualisierungen möglicherweise ein Veto erteilt werden. Eine einfache eingeschränkte Eigenschaft könnte also so aussehen:

PropertyType getFoo();
void setFoo(PropertyType value) throws PropertyVetoException;

Nehmen Sie das alles bitte mit einem Körnchen Salz. Die JavaBeans-Spezifikation ist alt, und C # -Eigenschaften (IMO) sind eine enorme Verbesserung gegenüber den auf "Namenskonventionen" basierenden Eigenschaften von Java. Ich versuche nur einen kleinen Kontext zu geben, ist alles!

Mike Clark
quelle
Es ist ein guter Punkt, aber die Unterscheidung zwischen einer Setter-Methode und einem ac # -Eigenschaftssetter ist signifikant genug, um für mich ein anderer Fall zu sein. Ebenso erzwingen die von Java geprüften Ausnahmen, dass der aufrufende Code erkennt, dass eine Ausnahme ausgelöst werden kann, sodass die Wahrscheinlichkeit geringer ist, dass dies jemanden überraschen wird.
Steven Evers
2

Der Punkt einer Immobilie ist das Prinzip des einheitlichen Zugangs , dh, ein Wert sollte über dieselbe Schnittstelle zugänglich sein, unabhängig davon, ob er durch Speichern oder Berechnen implementiert wird. Wenn Ihre Eigenschaft eine Ausnahme auslöst, die eine Fehlerbedingung darstellt, die außerhalb der Kontrolle des Programmierers liegt und die abgefangen und verarbeitet werden soll, zwingen Sie Ihren Client, zu wissen, dass der Wert durch Berechnung erhalten wird.

Andererseits sehe ich kein Problem bei der Verwendung von Zusicherungen oder zusicherungsähnlichen Ausnahmen, die dem Programmierer eine falsche Verwendung der API signalisieren sollen, anstatt abgefangen und behandelt zu werden. In diesen Fällen ist es aus Sicht des API-Benutzers nicht die richtige Antwort, die Ausnahme zu behandeln (daher ist es implizit wichtig, ob der Wert durch Berechnung oder Speicherung erhalten wird). Sie müssen den Code korrigieren, damit das Objekt nicht in einem ungültigen Zustand endet, oder Sie müssen den Code korrigieren, damit die Behauptung nicht ausgelöst wird.

dsimcha
quelle
Ich sehe nicht, wie "Sie Ihren Kunden zwingen, zu wissen, dass der Wert durch Berechnung erhalten wird" folgt. Natürlich kann der Zugriff auf den Speicher auch eine Ausnahme auslösen. Wie würden Sie den Unterschied zwischen den beiden überhaupt definieren?
Timwi
Ich glaube, dass der Unterschied darin besteht, dass das einfache Abrufen eines Werts aus einem Feld (Speicher) und das Ausführen einer harmlosen Aktion, z. B. das Platzieren in einer Variablen eines geeigneten Typs (dh ohne Casting), keine Ausnahme auslösen kann. In diesem Fall kann eine Ausnahme nur auftreten, wenn Sie anschließend etwas mit dem Wert ausgeführt haben. Wenn eine Ausnahme in einem Eigenschafts-Getter ausgelöst wird, kann in diesem Fall lediglich das Abrufen des Werts und das Platzieren in einer Variablen eine Ausnahme verursachen.
Dr. Wily's Apprentice
1

AFAIK, diese Anleitung basiert in erster Linie auf dem Gedanken, dass Eigenschaften möglicherweise zur Entwurfszeit verwendet werden. (ZB die Text-Eigenschaft in einer TextBox) Wenn die Eigenschaft eine Ausnahme auslöst, wenn ein Designer versucht, darauf zuzugreifen, hat VS keinen guten Tag. Sie erhalten eine Reihe von Fehlern, wenn Sie nur versuchen, den Designer zu verwenden, und für die UI-Designer werden sie nicht gerendert. Dies gilt auch für die Debug-Zeit, obwohl in einem Ausnahmeszenario nur "xxx Exception" angezeigt wird und VS IIRC nicht gestört wird.

Für POCOs schadet es nicht wirklich, aber ich scheue mich trotzdem davor, es selbst zu tun. Ich nehme an, die Leute werden häufiger auf Immobilien zugreifen wollen, daher sollten sie normalerweise kostengünstig sein. Eigenschaften sollten nicht die Arbeit von Methoden erledigen, sie sollten nur einige Informationen abrufen / festlegen und damit in der Regel fertig sein.

MIA
quelle
0

Obwohl eine Menge vom Kontext abhängt, würde ich generell vermeiden, irgendeine Art von zerbrechlicher Logik (einschließlich Ausnahmen) in Eigenschaften zu platzieren. Nur als ein Beispiel gibt es eine Menge Dinge, die Sie (oder eine Bibliothek, die Sie verwenden) tun könnten, die Reflexion verwenden, um Eigenschaften zu durchlaufen, was zu Fehlern führt, die Sie zur Entwurfszeit nicht erwartet haben.

Ich sage im Allgemeinen, obwohl es einige Male geben kann, in denen Sie auf jeden Fall etwas blockieren möchten, ohne sich über die Konsequenzen Gedanken zu machen. Sicherheit, denke ich, wäre der klassische Fall dort.

FinnNk
quelle