web-dev-qa-db-fra.com

Comment invoquer manuellement un événement?

J'ai la ligne suivante en C #:

_timer.ElapsedTick += _somefunction1;
_timer.ElapsedTick += _somefunction2;
_timer.ElapsedTick += _somefunction3;

Comment appeler toutes les méthodes abonnées à _timer.ElapsedTick sans spécifier la fonction _some? Quelque part le long de cette pseudo-ligne

invoke(_timer.ElapsedTick);

Votre aide est très appréciée.

Mettre à jour

Exemple de @ M.Babcock fonctionne. La méthode FireEvent fait la magie. Je vous remercie.

class InvokeFromMe
{
    public event EventHandler RaiseMe;
}
class MainClass
{
    public MainClass()
    {
        InvokeFromMe fromMe = new InvokeFromMe();
        fromMe.RaiseMe += fromMe_RaiseMe;
        fromMe.RaiseMe += fromMe_RaiseMe1;
        FireEvent(fromMe, "RaiseMe", null, EventArgs.Empty);
        //works

        System.Timers.Timer _timer = new System.Timers.Timer();
        _timer.Elapsed += _timer_Elapsed;
        FireEvent(_timer, "onIntervalElapsed", null, null);
        //throws exception
    }
    private void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("_timer_Elapsed raised");
    }
    private void fromMe_RaiseMe(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 0 Raised");
    }
    private void fromMe_RaiseMe1(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 1 Raised");
    }
    public void FireEvent(object onMe, string invokeMe, params object[] eventParams)
    {
        MulticastDelegate eventDelagate =
              (MulticastDelegate)onMe.GetType().GetField(invokeMe,
               System.Reflection.BindingFlags.Instance |
               System.Reflection.BindingFlags.NonPublic).GetValue(onMe);

        Delegate[] delegates = eventDelagate.GetInvocationList();

        foreach (Delegate dlg in delegates)
        {
            dlg.Method.Invoke(dlg.Target, eventParams);
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        MainClass m = new MainClass();
    }
}
19
Jeson Martajaya

Peut-on le faire avec du C # conventionnel? Non ( comme indiqué précédemment ). Mais utiliser la réflexion est possible. Voici un code testé basé sur la réponse à ce fil de discussion MSDN :

class InvokeFromMe
{
    public event EventHandler RaiseMe;
}

class Program
{
    static void Main(string[] args)
    {
        var fromMe = new InvokeFromMe();

        fromMe.RaiseMe += fromMe_RaiseMe;
        fromMe.RaiseMe += fromMe_RaiseMe1;
        fromMe.RaiseMe += fromMe_RaiseMe2;

        FireEvent(fromMe, "RaiseMe", null, EventArgs.Empty);
    }

    static void fromMe_RaiseMe(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 0 Raised");
    }
    static void fromMe_RaiseMe1(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 1 Raised");
    }
    static void fromMe_RaiseMe2(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 2 Raised");
    }

    public static void FireEvent(object onMe, string invokeMe, params object[] eventParams)
    {
        MulticastDelegate eventDelagate =
              (MulticastDelegate)onMe.GetType().GetField(invokeMe,
               System.Reflection.BindingFlags.Instance |
               System.Reflection.BindingFlags.NonPublic).GetValue(onMe);

        Delegate[] delegates = eventDelagate.GetInvocationList();

        foreach (Delegate dlg in delegates)
        {
            dlg.Method.Invoke(dlg.Target, eventParams);
        }
    } 

}

METTRE À JOUR

Je ne suis pas familier avec la classe System.Timer.Timer, donc je ne suis pas sûr de ce qui est différent de mon exemple fourni. Vous pourriez peut-être essayer quelque chose comme:

public static void FirePublicEvent(object onMe, string invokeMe, params object[] eventParams)
{
    MulticastDelegate eventDelagate =
          (MulticastDelegate)onMe.GetType().GetField(invokeMe,
           System.Reflection.BindingFlags.Instance |
           System.Reflection.BindingFlags.Public).GetValue(onMe);

    Delegate[] delegates = eventDelagate.GetInvocationList();

    foreach (Delegate dlg in delegates)
    {
       dlg.Method.Invoke(dlg.Target, eventParams);
    }
} 
20
M.Babcock

Vous ne pouvez pas invoquer un événement appartenant à un autre type. Un événement ne peut être invoqué que de l'intérieur de la classe qui le déclare. 

17
JaredPar

Ceci est un travail, vous ne pouvez pas parcourir l’événement Elapsed. Mais pour les invoquer tous, laissez le minuteur faire le travail. Ce code pour System.Timer, vous ne savez pas quel minuteur vous utilisez.

En supposant que la minuterie est déjà activée:

int interval = timer.Interval;
ElapsedEventHandler handler = null;
handler = (s,e) =>
{
    timer.Interval = interval; // put interval back to original value
    timer.Elapsed -= handler;
};
timer.Elapsed += handler;
timer.Interval = 1; // 1 millisecond, pretty much going to fire right now (as soon as you let it)

Quelque chose comme cela déclenchera les événements, mais votre intervalle d'origine sera redémarré. Vous devrez peut-être faire quelques calculs si vous souhaitez conserver le motif de tick initial.

2
Chuck Savage

Vous pouvez créer une fonction qui les exécute tous:

public void RunAllFuncs()
{
   _somefunction1();
   _somefunction2();
   _somefunction3();
}
1
SwDevMan81

Je pense que vous devez probablement utiliser InvokeMember:

public void GetMethod(string methodName){

            var args = new Object[] { [INSERT ARGS IF NECESSARY--SET TO NULL OTHERWISE] };
            try
            {
                var t = new [INSERT NAME OF CLASS THAT CONTAINS YOUR METHOD]();
                Type typeInfo = t.GetType();
                var result = typeInfo.InvokeMember(methodName, BindingFlags.InvokeMethod, null, t, args);
                return result;
            }
            catch (Exception ex)
            {
                return ex;
            }
}

Puis appelle ça comme ça:

_timer.ElapsedTick += GetMethod("[INSERT METHOD NAME AS STRING]");

Assurez-vous d'inclure ceci:

using System.Reflection;

Bonne chance!

1
Matt Cashatt

eh bien, je me retrouve ici à chercher comment lancer simplement un événement, ce qui n’a aucun argument personnalisé. Je sais que la question OP est différente! mais j'avais envie de partager, j'espère que cela aidera quelqu'un. 

Version simplifiée: 

 var Handler = EventNameHere;
        if (Handler != null)
        {
            Handler(this, EventArgs.Empty);
        }

Simplifier la version: 

 EventNameHere?.Invoke(this, EventArgs.Empty);
0
Danish

Basé sur la réponse de M.Babcock ci-dessus, avec de légères mises à jour de la méthode de réflexion.

Remplacé GetField par GetTypeInfo et GetDeclaredField, et dlg.Method par dlg.GetMethodInfo.

    using System.Reflection;

    ...

    public static void FireEvent(this object onMe, string invokeMe, params object[] eventParams)
    {
        TypeInfo typeInfo = onMe.GetType().GetTypeInfo();
        FieldInfo fieldInfo = typeInfo.GetDeclaredField(invokeMe);
        MulticastDelegate eventDelagate = (MulticastDelegate)fieldInfo.GetValue(onMe);

        Delegate[] delegates = eventDelagate.GetInvocationList();

        foreach (Delegate dlg in delegates)
        {
            dlg.GetMethodInfo().Invoke(dlg.Target, eventParams);
        }
    }
0
Felix