web-dev-qa-db-fra.com

Ordre d'exécution du gestionnaire d'événement

Si je configure plusieurs gestionnaires d'événements, comme ceci:

_webservice.RetrieveDataCompleted += ProcessData1;
_webservice.RetrieveDataCompleted += ProcessData2;

quel ordre les gestionnaires exécutent-ils lorsque l'événement RetrieveDataCompleted est déclenché? Sont-ils exécutés dans le même thread et séquentiellement dans l'ordre enregistré?

72
Phillip Ngan

Actuellement, ils sont exécutés dans l'ordre dans lequel ils sont enregistrés. Cependant, il s'agit d'un détail d'implémentation et je ne m'appuierais pas sur le fait que ce comportement resterait le même dans les versions futures, car il n'est pas requis par les spécifications.

111
Reed Copsey

La liste d’invocation d’un délégué est un ensemble ordonné de délégués dans lequel chaque élément de la liste appelle exactement l'une des méthodes invoquées par le délégué. Une liste d’invocations peut contient des méthodes en double. Pendant un invocation, un délégué appelle des méthodes dans l'ordre dans lequel ils apparaissent dans la liste d'invocation.

De là: Classe de délégué

48
Philip Wallace

Vous pouvez modifier la commande en détachant tous les gestionnaires, puis en les rattachant dans l'ordre souhaité.

public event EventHandler event1;

public void ChangeHandlersOrdering()
{
    if (event1 != null)
    {
        List<EventHandler> invocationList = event1.GetInvocationList()
                                                  .OfType<EventHandler>()
                                                  .ToList();

        foreach (var handler in invocationList)
        {
            event1 -= handler;
        }

        //Change ordering now, for example in reverese order as follows
        for (int i = invocationList.Count - 1; i >= 0; i--)
        {
            event1 += invocationList[i];
        }
    }
}
9
Naser Asadi

Ils sont gérés dans l'ordre dans lequel ils sont enregistrés. RetrieveDataCompleted est un Délégués de multidiffusion . Je regarde à travers le réflecteur pour essayer de vérifier, et il semble qu'un tableau est utilisé dans les coulisses pour suivre tout. 

8
Bob

L'ordre est arbitraire. Vous ne pouvez pas compter sur l'exécution des gestionnaires dans un ordre particulier d'une invocation à l'autre.

Edit: Et aussi - à moins que ce ne soit juste par curiosité - le fait que vous avez besoin de savoir est révélateur d'un problème de conception sérieux.

8
Rex M

Un MulticastDelegate a une liste chaînée de délégués, appelée liste d'invocation, composée d'un ou plusieurs éléments. Lorsqu'un délégué multidiffusion est appelé, les délégués de la liste d'appels sont appelés de manière synchrone dans leur ordre d'apparition. Si une erreur survient pendant l'exécution de la liste, une exception est levée.

2
Rahul

Si quelqu'un doit le faire dans le contexte d'un System.Windows.Forms.Form, voici un exemple inversant l'ordre des événements affichés.

using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace ConsoleApplication {
    class Program {
        static void Main() {
            Form form;

            form = createForm();
            form.ShowDialog();

            form = createForm();
            invertShownOrder(form);
            form.ShowDialog();
        }

        static Form createForm() {
            var form = new Form();
            form.Shown += (sender, args) => { Console.WriteLine("form_Shown1"); };
            form.Shown += (sender, args) => { Console.WriteLine("form_Shown2"); };
            return form;
        }

        static void invertShownOrder(Form form) {
            var events = typeof(Form)
                .GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic)
                .GetValue(form, null) as EventHandlerList;

            var shownEventKey = typeof(Form)
                .GetField("EVENT_SHOWN", BindingFlags.NonPublic | BindingFlags.Static)
                .GetValue(form);

            var shownEventHandler = events[shownEventKey] as EventHandler;

            if (shownEventHandler != null) {
                var invocationList = shownEventHandler
                    .GetInvocationList()
                    .OfType<EventHandler>()
                    .ToList();

                foreach (var handler in invocationList) {
                    events.RemoveHandler(shownEventKey, handler);
                }

                for (int i = invocationList.Count - 1; i >= 0; i--) {
                    events.AddHandler(shownEventKey, invocationList[i]);
                }
            }
        }
    }
}
2

Au cours d'une invocation, les méthodes sont appelées dans l'ordre dans lequel elles apparaissent dans la liste d'appels.

Mais personne ne dit que la liste d’invocation maintient les délégués dans le même ordre d’ajout .. .. L’ordre d’invocation n’est donc pas garanti.

0
ruslanu