2009-05-13 16 views
2

Ich habe eine benutzerdefinierte Sammlung, der ich ein ValidateItem-Ereignis hinzufügen möchte. Dieses ValidateItem-Ereignis wird immer dann aufgerufen, wenn ein Element in der benutzerdefinierten Sammlung hinzugefügt oder aktualisiert wird.C# Custom EventArgs Frage

Ich möchte zulassen, dass abgeleitete Klassen in der Lage sind, das Ereignis zu abonnieren und ihre eigene Logik dafür zu bestimmen, ob ein Element "gültig" ist oder nicht und dass es der Sammlung hinzugefügt wird, wenn es "ungültig" ist.

Aber ich versuche herauszufinden, wie ich den Anrufer zu dem Ereignis wissen lassen kann, was vor sich geht und wie man die Information darüber weiterleitet, was vor sich geht.

Meine benutzerdefinierten Ereignisvariablen erben von CancelEventArgs, so dass ich die Möglichkeit habe, das Cancel-Bit zurück an den Aufrufer zu übergeben. Aber ich habe noch nie Fälle gesehen, in denen Fehlerinformationen (Fehlercodes, Nachrichten usw.) auf diese Weise zurückgegeben werden, also frage ich mich, ob dies nicht der beste Ansatz ist.

Sollte ich einfach irgendwelche Fehlerdaten hinzufügen, die ich an meine benutzerdefinierte Eventargs-Klasse zurückgeben möchte, gibt es gute Gründe dafür oder dagegen? Oder gibt es andere, bessere Möglichkeiten, dies zu erreichen?

Hier ist meine EventArgs Klasse:

public delegate void ItemValidationEventHandler(object sender, ItemValidationEventArgs e); 

public class ItemValidationEventArgs : CancelEventArgs 
{ 
    public ItemValidationEventArgs(object item, ObjectAction state, EventArgs e) 
    { 
     Item = item; 
     State = state; 
     EventArgs = e; 
    } 

    public ItemValidationEventArgs(object item, ObjectAction state) : this(item, state, new EventArgs()) 
    { 
    } 

    public ItemValidationEventArgs() : this(null, ObjectAction.None, new EventArgs()) 
    { 
    } 

    // is there a better way to pass this info? 
    public string ErrorMessage {get; set;} 
    public int ErrorNumber {get;set;} 

    public object Item { get; private set; } 
    public ObjectAction State { get; private set; } 

    public EventArgs EventArgs { get; private set; } 
} 

UPDATE: Ich nehme an eine andere andere Möglichkeit, so etwas zu verwenden wäre:

virtual bool Validate(object item, ObjectAction action, out string errorMessage) 

Methode in den abgeleiteten Klassen. Obwohl ich dazu tendiere, Parameter zu vermeiden ...

Wenn jemand irgendwelche Ideen über die Vor- und Nachteile jedes Ansatzes hat, würde ich mich freuen, sie zu hören!

Danke, Max

Antwort

3

Die Verwendung von Ereignissen ist wahrscheinlich nicht der beste Entwurf.

Da es sich um eine Vererbungs Klasse ist, die dieses Verhalten werden überschreiben würde, sollte das Verfahren gekennzeichnet werden als geschützt und virtuell:

protected virtual bool Validate(object item); 

Ich mag auch nicht out auf Parametern, so nach Ihrer ursprünglichen Instinkte Verwenden Sie EventArgs, sollten Sie wahrscheinlich eine Klasse erstellen, um die Ergebnisse Ihrer Validierung zu kapseln.

Beispiel:

class ValidationResult 
{ 
    public string ResultMessage{get;set;} 
    public bool IsValid {get;set;} 
} 

Ihre Methode wäre dann:

protected virtual ValidationResult Validate(object item) 
{ 
    ValidationResult result = new ValidationResult(); 

    // validate and set results values accordingly 

    return result; 
} 

Die Vor- und Nachteile der Verwendung dieser über Ereignisse, die Ereignisse bestimmt sind, verwendet werden, wenn Sie eine Aktion veröffentlichen möchten oder Informationen für mehrere Abonnenten. Die Abonnenten sind Klassen, von denen Sie nichts wissen. Es ist dir egal, wer sie sind oder was sie tun. Sie sollten Informationen auch nicht wirklich an die benachrichtigende Klasse zurückgeben. Sie sollten nur die Ereignisinformationen verarbeiten, die ihnen gegeben wurden.

In Ihrer Instanz ist Ihre geerbte Klasse Ihr einziger Abonnent. Darüber hinaus möchten Sie nützliche Informationen an die Elternklasse zurückgeben können. Vererbung passt viel besser zu diesem gewünschten Verhalten und ermöglicht Ihnen auch die einfache Implementierung verschiedener Arten von Validierungsklassen. Bei Ereignissen müssten Sie weiterhin Code eingeben, um Event-Handler immer wieder anzuhängen (sehr hässliche IMO).

+0

Ziemlich gut gesagt +1 –

0

Nun, wenn Sie Ihre eigenen benutzerdefinierten Validierung Ereignisse erstellen, zusammen mit Event args benutzerdefinierten Validierung, würde ich annehmen, dass Sie Status/Fehlercodes zurücklaufen eher würde es vorziehen, als Ausnahmen, wenn etwas zu werfen validiert nicht.

In diesem Fall, wenn Sie eine Validierung wünschen, die keine Ausnahmen auslöst, dann würde ich die Felder, die Sie für Ihre benutzerdefinierten Ereignisargumente benötigen, hinzufügen - sie sind bereits benutzerdefiniert, es gibt also keinen Grund, nicht zu verlängern sie Ihre Bedürfnisse :-)

Marc

0

Ein paar schnelle Gedanken gerecht zu werden:

ich würde die Eigenschaften machen nur lesbar zu den „normalen“ Muster von EventArgs Klassen entsprechen.

Möglicherweise sollten die Eigenschaften, die sich auf Fehlerinformationen beziehen, in einige ErrorInformation-Klassen eingeschlossen werden (das würde die Weitergabe dieser Informationen an andere Methoden erleichtern).

Eine Frage: Wofür verwenden Sie die EventArgs-Eigenschaft?

+0

Ich denke, readonly würde in diesem Fall nicht funktionieren. Wenn du CancelEventArgs ansiehst, wird bool Cancel nicht readonly ... und das wird verwendet, um Informationen an den Aufrufer weiterzuleiten, also erweitere ich das wirklich nur ein wenig. Etwas erscheint mir einfach als "lustig" in Bezug auf diese Herangehensweise, ich kann es nicht wirklich sagen. Ich verwende die Ereignisargumente, um ein Objekt (Element) an die validate-Methode zu übergeben, die validate-Methode macht alles, was sie will ... im einfachsten Beispiel prüft sie, ob das Element noch nicht in der Sammlung existiert. und dann Cancel bool und möglicherweise alle Fehlermeldungen zurück. –

+0

Natürlich; Ich dachte in die falsche Richtung ... Ein anderes Ding kam mir in den Sinn; Was passiert, wenn es zwei verschiedene Listener für das Validierungsereignis gibt, bei denen Cancel = true gesetzt wird und die andere Gruppe Cancel = false?Ich habe das gleiche Gefühl wie du; da ist etwas Schlechtes, das hier unter der Oberfläche lauert; o) –

0

Benutzerdefinierte Ereignisargumente werden speziell verwendet, um Informationen an und von den Ereignishandlern weiterzuleiten, also ja, sie sind ein guter Ort, um sie zu platzieren.

Die andere Option wäre, eine Ausnahme zu werfen - das ist ziemlich umständlich, sollte aber verhindern, dass andere Event-Handler für das Ereignis ausgeführt werden.

0

EventArgs und CancelEventArgs haben keine Mitglieder zum Übertragen von Informationen an den Abonnenten. Sie würden normalerweise von einer dieser Klassen erben und ein oder mehrere Mitglieder hinzufügen, um Informationen zu tragen. Sie können Ihre Klasse auch generisch machen, so dass Sie keine neue EventArgs-Klasse erstellen müssen, wenn Sie unterschiedliche Daten senden müssen.

Schließlich können Sie anstelle des eigenen ItemValidationEventHandler-Delegattyps EventHandler<T> verwenden, wobei T der Typ Ihres EventArgs-Parameters ist.

Sie brauchen auch nicht das EventArgs = e Mitglied.

1

Ich denke nicht, was du beschreibst wirklich passt der Beobachter, beobachtbare Muster, die Sie normalerweise mit Ereignissen sehen würden.

Da dies abgeleitete Klassen sind, würde ich wahrscheinlich versuchen, die Validierungsmethode der Objekte zu virtualisieren und die Kinder eine bestimmte Validierungsroutine bereitstellen zu lassen.

+0

Ich denke, das ist ein Teil dessen, was mich an diesem Ansatz stört. Aber verletzen die CancelEventArgs mit einer modifizierbaren Cancel-Eigenschaft nicht bereits das Muster? Also, hypothetisch, was ist falsch daran, ein paar zusätzliche Daten hinzuzufügen? –

+0

Das Ereignis "Abbrechen" teilt anderen Ereignissen in der Leitung mit, dass das Ereignis abgebrochen wurde. Andere Beobachter wissen, dass sie nichts tun müssen. Eines der Probleme mit Ereignissen ist, dass alle Teilnehmer in einer nicht-deterministischen Reihenfolge aufgerufen werden, und das ist nicht genau das, was Sie hier wollen, Sie wollen nur ein Objekt validieren genannt. –