Je fais une petite application multi-thread qui utilise des sockets asynchrones TCP, mais je vais aller droit au but: j'utilise un événement personnalisé pour lire une valeur à partir d'un formulaire et le délégué utilisé par les retours d'événement une chaîne lorsque vous avez terminé.
Ma question est la suivante: est-ce correct? est-il possible de renvoyer les valeurs des événements? ou y a-t-il une meilleure façon de faire cela? (comme utiliser un simple délégué au formulaire pour lire les valeurs)
Il est souvent difficile de renvoyer des valeurs d'événements. En pratique, j'ai trouvé beaucoup plus facile d'inclure une propriété accessible en écriture sur un ensemble de EventArgs personnalisés transmis à l'événement, puis vérifiés après le déclenchement de l'événement - similaire à la propriété Cancel de l'événement WinForms FormClosing.
Je ne pense pas que ce soit une bonne idée ... les événements sont essentiellement des délégués multicast, il peut donc y avoir plusieurs gestionnaires. Quelle valeur de retour allez-vous prendre dans ce cas?
L'exemple le plus proche auquel je puisse penser est l'événement FormClosing dans WinForms. Il permet au formulaire d'annuler l'événement en définissant la propriété eventArgs.Cancel sur true. Pour que vous puissiez faire quelque chose de similaire, vous définiriez votre propre classe d'arguments d'événement avec la valeur de retour comme propriété de cette classe. Passez ensuite un objet args event à chaque fois que vous le déclenchez. Celui qui a déclenché l'événement peut inspecter l'objet d'argument d'événement pour la valeur de retour. Les autres destinataires de l'événement peuvent également inspecter ou modifier l'objet Arguments d'événement.
Update: Je viens de rencontrer l'événement AppDomain.AssemblyResolve , et il semble que ce soit un événement qui renvoie une valeur. Il semble que vous ayez juste besoin de déclarer un type de délégué qui renvoie une valeur, puis de définir votre événement avec ce type de délégué. Je n'ai cependant pas essayé de créer mon propre événement comme celui-ci. Un avantage à utiliser une propriété sur l'argument d'événement est que tous les abonnés à l'événement peuvent voir ce que les abonnés précédents ont renvoyé.
Je sais que cela fait des siècles après le post, mais j'ai pensé ajouter un commentaire avec un code pour expliquer la réponse de Dustin Campbell si quelqu'un d'autre venait à trouver ce fil. Je suis tombé sur ce post en essayant de décider quelle serait la meilleure pratique et c'est ce que l'on entend par la réponse.
Créez votre propre classe de gestionnaire d'événements personnalisée
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 ;
}
}
Ainsi, lorsque vous créez votre délégué d'événement, vous utilisez les arguments d'événement créés comme ceci.
public delegate void myCustomeEventHandler(object sender, myCustomeEventArgs e);
Et dans la classe qui lève l'événement, vous déclarez l'événement.
public event myCustomeEventHandler myCustomeEvent;
Ainsi, lorsque vous déclenchez l'événement dans votre classe, celle-ci l'écoute, vous pouvez simplement l'indiquer dans le corps de l'événement défini e.DoOverride = true; comme il sera déclaré dans la classe qui déclenche l'événement.
Evénement d'incendie par exemple:
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
}
}
Remarque: seul le dernier événement renvoie le résultat.
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;
}
}
Je ne sais pas si c'est la meilleure pratique mais je l'ai fait de cette façon.
Func<DataRow, bool> IsDataValid;
// some other code ....
isValid = true;
if (IsDataValid != null)
{
foreach (Func<DataRow, bool> func in IsDataValid.GetInvocationList())
{
isValid &= func(Row);
}
}
Si event renvoie une valeur et que plusieurs gestionnaires sont enregistrés, l'événement renvoie la valeur de résultat du dernier gestionnaire appelé. Cherchez un exemple à http://blogs.msdn.com/b/deviations/archive/2008/11/27/event-handlers-returning-values.aspx
J'ai mis en boucle les propriétés des EventArgs comme ceci et ai extrait ses valeurs X et Y.
void privé navBarControl1_Click (expéditeur d'objet, 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);
}
}