web-dev-qa-db-fra.com

Renvoyez une valeur de retour via un EventHandler

Im essayant d'écrire dans une API et j'ai besoin d'appeler un gestionnaire d'événements lorsque j'obtiens des données d'une table. Quelque chose comme ça:

    public override bool Run(Company.API api)
    {
        SomeInfo _someInfo = new SomeInfo();

        if (_someInfo.Results == 1)
            return true;
        else
            return false;

        using (MyTable table = new MyTable(api))
        {
            table.WhenData += new EventHandler<DataEventArgs<Record>>(table_WhenData);
            table.WhenDead += new EventHandler<EventArgs>(table_WhenDead);
            table.Start();
        }

    public void table_WhenData(object sender, DataEventArgs<Record> e)
    {
        return true;
    }

Le problème que j'ai, c'est que je ne sais pas comment renvoyer une valeur de retour de table_WhenData à la méthode Run.

Ive a essayé de nombreuses façons (comme essayer de passer _someInfo à la méthode) mais je n'arrive pas à avoir la bonne syntaxe.

Toute suggestion est grandement appréciée.

34
Leroy Jenkins

Le modèle courant ici n'est pas de renvoyer des données du gestionnaire d'événements, mais d'ajouter des propriétés à votre objet argument d'événement afin que le consommateur de l'événement puisse définir les propriétés auxquelles l'appelant peut alors accéder. Ceci est très courant dans le code de gestion de l'interface utilisateur; vous voyez le concept d'événement Annuler partout.

Ce qui suit est un pseudo-code et n'est pas prêt à être compilé. Son intention est de montrer le motif.

public class MyEventArgs : EventArgs
{
   public bool Cancel{get;set;}
}

public bool fireEvent()
{
    MyEventArgs e=new MyEventArgs();

    //Don't forget a null check, assume this is an event
    FireEventHandler(this,e);

    return e.Cancel;
}

public HandleFireEvent(object sender, MyEventArgs e)
{
 e.Cancel=true;
}

Modifier

J'aime la façon dont Jon Skeet a formulé ceci: rendre le EventArgs mutuable. Autrement dit, le consommateur de l'événement peut modifier l'état de l'objet EventArgs, ce qui permet au déclencheur de l'événement d'accéder à ces données.

50
JoshBerke

Je sais que c'est un ancien poste, mais juste au cas où quelqu'un le trouverait, il est certainement possible de le faire. Vous déclarez votre propre délégué qui renvoie une valeur, puis basez l'événement sur ce nouveau délégué. Voici un exemple:

Dans le cas du déclarant/éditeur de l'événement:

// the delegate
public delegate string ReturnStringEventHandler(object sender, EventArgs args);
// the event
public event ReturnStringEventHandler StringReturnEvent;
// raise the event
protected void OnStringReturnEvent(EventArgs e)
    {
        if (StringReturnEvent != null)  // make sure at least one subscriber
              // note the event is returning a string
              string myString = StringReturnEvent(this, e);
    }

Dans le cas d'un abonné à l'événement:

// Subscribe to event, probably in class constructor / initializer method
StringReturnEvent += HandleStringReturnEvent;

// Handle event, return data
private string HandleStringReturnEvent(object sender, EventArgs e)
{
    return "a string to return";
}

.NET en fournit un exemple dans l'événement AssemblyResolve, qui utilise le délégué ResolveEventHandler pour renvoyer des données, dans ce cas une référence à l'assembly souhaité. Article MSDN sur l'événement AssemblyResolve

J'ai personnellement utilisé à la fois l'événement AssemblyResolve et la technique de délégué personnalisé pour renvoyer les données d'un événement, et ils fonctionnent tous les deux comme prévu sur Visual Studio 2010.

28
AFischbein

La seule façon de le faire est de rendre mutable l'un des arguments (de préférence les "arguments" plutôt que l'expéditeur). Si ce n'est pas déjà modifiable, vous avez essentiellement des problèmes - il n'y a tout simplement aucun moyen de diffuser les informations.

(D'accord, il y a un moyen - vous pouvez garder l'argument d'événement lui-même immuable, mais en faire un membre d'une méthode qui finit par appeler un délégué enregistré par le code provoquant l'événement en premier lieu. Mais c'est horrible ...)

19
Jon Skeet

Une solution simple consiste à utiliser une fermeture:

public override bool Run() {
    SomeInfo someInfo = ...
    table.WhenData += (obj, args) => {
        someInfo.Return = something
    };
}
1
Igor ostrovsky