web-dev-qa-db-de.com

Einen Wert von einem Ereignis zurückgeben - gibt es dafür eine gute Praxis?

Ich mache eine kleine Multithread-App, die asynchrone TCP - Sockets verwendet, aber ich komme zur Sache: Ich verwende ein benutzerdefiniertes Ereignis, um einen Wert aus einem Formular zu lesen, und der vom Ereignis verwendete Delegat wird zurückgegeben eine Zeichenfolge, wenn Sie fertig sind.

Meine Frage hier ist: ist das richtig? Ist es in Ordnung, Werte aus den Ereignissen zurückzugeben? oder gibt es einen besseren Weg, dies zu tun? (wie ein einfacher Delegat für das Formular, um die Werte zu lesen)

36
Hugo

Es ist oft unangenehm, Werte aus Ereignissen zurückzugeben. In der Praxis habe ich es viel einfacher gefunden, eine beschreibbare Eigenschaft in eine Gruppe von benutzerdefinierten EventArgs aufzunehmen, die an das Ereignis übergeben und dann nach dem Auslösen des Ereignisses überprüft werden - ähnlich der Cancel-Eigenschaft des WinForms FormClosing-Ereignisses.

37
Dustin Campbell

Ich denke nicht, dass dies eine gute Idee ist ... Ereignisse sind im Wesentlichen Multicast-Delegierte, daher kann es mehrere Handler geben. Welchen Rückgabewert erhalten Sie in diesem Fall?

28
Thomas Levesque

Das engste Beispiel, das ich mir vorstellen kann, ist das FormClosing-Ereignis in WinForms. Das Formular kann das Ereignis abbrechen, indem die eventArgs.Cancel -Eigenschaft auf true festgelegt wird. Damit Sie etwas Ähnliches tun können, definieren Sie Ihre eigene Event-Klasse-Klasse mit dem Rückgabewert als Eigenschaft für diese Klasse. Übergeben Sie dann ein Ereignisobjektobjekt, wenn Sie das Ereignis auslösen. Wer das Ereignis angesprochen hat, kann das Ereignisobjektobjekt auf den Rückgabewert untersuchen. Andere, die das Ereignis erhalten, können das Ereignisobjektobjekt auch überprüfen oder ändern.

Update: Ich bin gerade über das AppDomain.AssemblyResolve -Ereignis gestoßen, und es scheint ein Ereignis zu sein, das einen Wert zurückgibt. Es scheint, dass Sie nur einen Delegattyp deklarieren müssen, der einen Wert zurückgibt, und dann Ihr Ereignis mit diesem Delegattyp definieren. Ich habe jedoch noch nicht versucht, so ein eigenes Event zu erstellen. Ein Vorteil bei der Verwendung einer Eigenschaft für das Ereignisargument besteht darin, dass alle Abonnenten des Ereignisses sehen können, was vorherige Abonnenten zurückgegeben haben.

16
Don Kirkby

Ich weiß, das ist Ewigkeit nach dem Beitrag, aber ich dachte daran, einen Kommentar mit Code hinzuzufügen, um die Antwort von Dustin Campbell zu erklären, falls jemand anderes auf diesen Thread trifft. Ich bin auf diesen Beitrag gestoßen, als ich versuchte zu entscheiden, was die beste Methode wäre. Dies ist, was mit der Antwort gemeint ist.

Erstellen Sie Ihre eigene benutzerdefinierte Ereignishandlerklasse

public class myCustomeEventArgs:EventArgs
{
    public bool DoOverride { get; set; }
    public string Variable1 { get; private set; }
    public string Variable2{ get; private set; }

    public myCustomeEventArgs(string variable1 , string variable2 )
    {
        DoOverride = false;
        Variable1 = variable1 ;
        Variables = variable2 ;
    }
}

Wenn Sie also einen Ereignisdelegierten erstellen, verwenden Sie Ihre erstellten Ereignisargumente wie folgt.

public delegate void myCustomeEventHandler(object sender, myCustomeEventArgs e);

Und in der Klasse, die das Ereignis erhebt, deklarieren Sie das Ereignis.

public event myCustomeEventHandler myCustomeEvent;

Wenn Sie also das Ereignis in Ihrer Klasse auslösen, können Sie die Klasse, die auf das Ereignis wartet, einfach im Hauptteil des Ereignisses festlegen. E.DoOverride = true; wie es in der Klasse angegeben wird, die das Ereignis abfeuert.

Feuerereignis zum Beispiel:

if(myCustomeEvent != null)
{
    var eventArgs = new myCustomeEventArgs("Some Variable", "Another Varaible");
    myCustomeEvent(this, eventArgs);
    //Here you can now with the return of the event work with the event args
    if(eventArgs.DoOverride)
    {
       //Do Something
    }
}
13
Riaan Swart

Hinweis: Nur das letzte Ereignis gibt das Ergebnis zurück.

class Program
{
static event Func<string, bool> TheEvent;

    static void Main(string[] args)
    {
        TheEvent += new Func<string, bool>(Program_TheEvent);
        TheEvent +=new Func<string,bool>(Program_TheEvent2);
        TheEvent += new Func<string, bool>(Program_TheEvent3);
        var r = TheEvent("s"); //r == flase (Program_TheEvent3)
    }

    static bool Program_TheEvent(string arg)
    {
        return true;
    }

    static bool Program_TheEvent2(string arg)
    {
        return true;
    }

    static bool Program_TheEvent3(string arg)
    {
        return false;
    }        
}
9
Alatey

Ich weiß nicht, ob dies die beste Methode ist, aber ich habe es so gemacht.

   Func<DataRow, bool> IsDataValid;

   // some other code ....

   isValid = true;
   if (IsDataValid != null)
   {
      foreach (Func<DataRow, bool> func in IsDataValid.GetInvocationList())
      {
         isValid &= func(Row);
      } 
   }
8
Henk

Wenn event einen Wert zurückgibt und mehrere Handler registriert sind, gibt das Ereignis den Ergebniswert des zuletzt aufgerufenen Handlers zurück. Ein Beispiel finden Sie unter http://blogs.msdn.com/b/deviations/archive/2008/11/27/event-handlers-returning-values.aspx

1
sammybar

Ich habe die Eigenschaften der EventArgs so geschlungen und die X- und Y-Werte herausgezogen. 

private void navBarControl1_Click (Objektsender, EventArgs e) { int _x = 0; int _y = 0;

        Type t = e.GetType();
        IList<PropertyInfo> props = new List<PropertyInfo>(t.GetProperties());

        foreach (PropertyInfo prop in props)
        {
            if (prop.Name == "X")
            {
                object propValue = prop.GetValue(e, null);
                _x = Convert.ToInt32(propValue);
            }
            if (prop.Name == "Y")
            {
                object propValue = prop.GetValue(e, null);
                _y = Convert.ToInt32(propValue);
            }
        }
0
user1218233