2009-06-25 17 views
8

Ich habe eine Klasse Mitarbeiter. Ich möchte es validieren(), bevor ich es speichere, um sicherzustellen, dass alle Felder mit gültigen Werten gefüllt sind. Der Benutzer der Klasse kann Validate() aufrufen, bevor sie Save() aufrufen, oder sie können Save() direkt aufrufen und Save() wird dann Validate() aufrufen und wahrscheinlich eine Exception auslösen, wenn die Validierung fehlschlägt.Bewährtes Verfahren, um zusätzliche Informationen aus einer Validate-Funktion zurückzugeben

Jetzt ist meine (Haupt-) Frage das;
Wenn meine Validate() - Funktion einen einfachen Bool zurückgibt, wie sage ich dann dem Benutzer der Klasse, was falsch ist, dh "Email nicht ausgefüllt", "ID nicht eindeutig" usw. Für die Zwecke möchte ich nur die Fehlerzeichenfolgen, die an den menschlichen Benutzer übergeben werden, aber das Prinzip ist das gleiche, wenn ich eine Liste von Fehlercodes haben wollte (abgesehen davon, dass die Verwendung einer Bitmap logischer ist).

  • Ich könnte einen Out-Parameter in meiner Validate-Funktion verwenden, aber ich verstehe, dass dies verpönt ist.
  • Anstatt eine Bool zurückgeben, konnte ich ein String-Array von meiner Funktion und nur testen, ob es leer war (dh keine Fehler) - aber das scheint chaotisch und nicht richtig.
  • Ich könnte ein Struct erstellen, nur um von dieser Methode zurückzukehren, einschließlich einer Bool und ein String-Array mit Fehlermeldungen, aber scheint nur klobig.
  • Ich könnte ein Bitmap der Fehlercodes anstelle eines Bool zurückgeben und nachschlagen, aber das scheint ziemlich übertrieben.
  • Ich könnte eine öffentliche Eigenschaft "ValidationErrors" auf dem Objekt erstellen, das die Fehler enthalten würde. Das würde jedoch davon abhängen, dass ich Validate() aufruft, bevor ich es lese oder explizit Validate von der Property() aufruft, was ein wenig verschwenderisch ist.
  • Mein spezifisches Programm ist in C#, aber das sieht wie eine ziemlich generische "Best Practice" -Frage aus und ich bin sicher, dass ich die Antwort darauf wissen sollte. Jeder Rat wurde dankbar angenommen.

    Antwort

    5

    Ich würde wahrscheinlich für die Bitmap-Option gehen.Einfach

    [Flags] 
    public enum ValidationError { 
        None = 0, 
        SomeError = 1, 
        OtherError = 2, 
        ThirdError = 4 
    } 
    

    ... und in der anruf Code einfach wie folgt:

    ValidationError errCode = employee.Validate(); 
    if(errCode != ValidationError.None) { 
        // Do something 
    } 
    

    scheint nett und kompakt zu mir.

    +0

    +1 - Sie haben mich dazu geschlagen. –

    +0

    Sie haben Recht, ich sollte über meine Fehlermeldungen strukturiert sein und ein zentrales Repository für sie haben, wo ich sie nach der "benutzerfreundlichen" Version etc. suchen kann. – Frans

    +0

    Einziger Schwachpunkt, den ich mit dieser Lösung habe, ist, dass ich nicht würde benutze '0' als Wert des ersten Enums, das mit' [Flag] 'versehen ist ... – IAbstract

    6

    Ich könnte ein Struct erstellen, nur um von dieser Methode zurückzukehren, einschließlich eines Bool und eines String-Array mit Fehlermeldungen, aber scheint nur klobig.

    Warum scheint es klobig? Das Erstellen eines geeigneten Typs zum Einkapseln der Informationen ist perfekt. Ich würde nicht unbedingt eine Zeichenfolge verwenden, um solche Informationen zu kodieren. Ein Enum kann besser geeignet sein.

    Eine Alternative wäre die Unterklasse des Rückgabetyps und die Bereitstellung einer zusätzlichen untergeordneten Klasse für jeden Fall - wenn dies angemessen ist. Wenn mehr als ein Fehler gemeldet werden kann, ist ein Array in Ordnung. Aber ich würde dies auch in einem eigenen Typ einkapseln.

    Das allgemeine Muster könnte wie folgt aussehen:

    class ValidationInfo { 
        public bool Valid { get; private set; } 
        public IEnumerable<Failure> Failures { get; private set; } 
    } 
    
    1

    Ich würde das Muster der TryParse Methoden folgen und ein Verfahren mit dieser Signatur verwenden:

    public bool TryValidate(out IEnumerable<string> errors) { ... } 
    

    Eine weitere Option ist die Validierung ziehen Code aus dem Objekt in seine eigene Klasse, möglicherweise aufbauend auf dem Spezifikationsmuster.

    public class EmployeeValidator 
    { 
        public bool IsSatisfiedBy(Employee candidate) 
        { 
         //validate and populate Errors 
        } 
        public IEnumerable<string> Errors { get; private set; } 
    } 
    
    0

    Wir verwenden die Spring-Validierung zusammen mit einem Windows Forms-Fehleranbieter.

    Unsere Validierungsfunktion gibt also ein Dictionary mit einer Kontroll-ID und einer Fehlermeldung (für jeden Validierungsfehler) zurück. Der Fehleranbieter zeigt die Fehlermeldung in einem Popup-Feld in der Nähe des Steuerelements an, das den Fehler verursacht hat.

    Ich habe einige andere Validierungsschemata in der Vergangenheit benutzt - aber diese funktioniert wirklich gut.

    1

    Ich habe es einen guten Ansatz gefunden, einfach eine Methode (oder eine Eigenschaft, da C# hat nette Unterstützung dafür), die alle Validierungsfehlermeldungen in einer Art von sinnvollen, einfach zu verwenden Format, wie eine Liste von Saiten.

    Auf diese Weise können Sie auch Ihre Validierungsmethode zur Rückgabe von Bools beibehalten.

    2

    Klingt wie Sie eine generische Klasse benötigen:

    public sealed class ValidationResult<T> 
    { 
        private readonly bool _valid; // could do an enum {Invalid, Warning, Valid} 
        private readonly T _result; 
        private readonly List<ValidationMessage> _messages; 
    
        public ValidationResult(T result) { _valid = true; _result = result; _messages = /* empty list */; } 
    
        public static ValidationResult<T> Error(IEnumerable<ValidationMessage> messages) 
        { 
         _valid = false; 
         _result = default(T); 
         _messages = messages.ToList(); 
        } 
    
        public bool IsValid { get { return _valid; } } 
        public T Result { get { if(!_valid) throw new InvalidOperationException(); return _result; } } 
        public IEnumerable<ValidationMessage> Messages { get { return _messages; } } // or ReadOnlyCollection<ValidationMessage> might be better return type 
    
        // desirable things: implicit conversion from T 
        // an overload for the Error factory method that takes params ValidationMessage[] 
        // whatever other goodies you want 
        // DataContract, Serializable attributes to make this go over the wire 
    } 
    
    +0

    Ich würde nur vielleicht einen Verweis auf was fehlgeschlagen hinzufügen, wenn es war Attribut Ebene Regel, die dann Bezug auf diese Eigenschaft faild, wenn es Entity Wide war dann Bezug auf Entität etc. – epitka

    1

    Sie einen Blick auf Rockford Lhotka des CSLA nehmen könnte, die umfangreiche Business-Regel/Validierung Tracking forr Geschäftsobjekte in ihm hat.

    www.lhotka.net

    1

    ich mit Chris W. zustimmen, fragte ich die gleichen Fragen, bevor Rocky`s Expert C# Business Objects zu lesen.

    Er hat eine hervorragende Möglichkeit, Geschäftsvalidierungsregeln zu handhaben. Die Validierung wird durchgeführt, nachdem jede Eigenschaft festgelegt wurde. Wenn eine Regel verletzt wird, wird der Status des Objekts InValid.

    Ihre Business Class kann die IDataError-Schnittstelle implementieren. Wenn Sie Ihre UI-Steuerelemente an die Eigenschaften Ihres Geschäftsobjekts binden, werden Sie Ihr ErrorProvider-Steuerelement über alle fehlerhaften Regeln für Ihr Objekt informieren.

    Ich würde wirklich empfehlen, dass Sie sich die Zeit nehmen und den Validierungsabschnitt betrachten.

    Verwandte Themen