Comment faire en C# d'Événements de derrière les coulisses?
Je suis à l'aide de C#, .NET 3.5. Je comprends comment utiliser les événements, la façon de les déclarer dans ma classe, comment les connecter à partir de quelque part d'autre, etc. Un exemple artificiel:
public class MyList
{
private List<string> m_Strings = new List<string>();
public EventHandler<EventArgs> ElementAddedEvent;
public void Add(string value)
{
m_Strings.Add(value);
if (ElementAddedEvent != null)
ElementAddedEvent(value, EventArgs.Empty);
}
}
[TestClass]
public class TestMyList
{
private bool m_Fired = false;
[TestMethod]
public void TestEvents()
{
MyList tmp = new MyList();
tmp.ElementAddedEvent += new EventHandler<EventArgs>(Fired);
tmp.Add("test");
Assert.IsTrue(m_Fired);
}
private void Fired(object sender, EventArgs args)
{
m_Fired = true;
}
}
Cependant, ce que je ne pas comprendre, c'est quand on déclare un gestionnaire d'événement
public EventHandler<EventArgs> ElementAddedEvent;
Il n'est jamais initialisée - alors quoi, exactement, est ElementAddedEvent? En quoi est-il point? Le suivant ne fonctionnera pas, parce que le Gestionnaire n'est jamais initialisée:
[TestClass]
public class TestMyList
{
private bool m_Fired = false;
[TestMethod]
public void TestEvents()
{
EventHandler<EventArgs> somethingHappend;
somethingHappend += new EventHandler<EventArgs>(Fired);
somethingHappend(this, EventArgs.Empty);
Assert.IsTrue(m_Fired);
}
private void Fired(object sender, EventArgs args)
{
m_Fired = true;
}
}
Je remarque qu'il y a un Gestionnaire d'événements.CreateDelegate(...), mais toutes les signatures de méthode suggère qu'il est seulement utilisé pour la fixation des Délégués à un Gestionnaire d'événements à travers le ElementAddedEvent += new EventHandler(MyMethod).
Je ne suis pas sûr si ce je suis en train de faire va les aider... mais finalement, je voudrais venir avec un résumé parent DataContext dans LINQ dont les enfants peuvent s'inscrire la table des Types qu'ils veulent ", a observé", donc je peux avoir des événements tels que BeforeUpdate et AfterUpdate, mais qui sont spécifiques à des types. Quelque chose comme ceci:
public class BaseDataContext : DataContext
{
private static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> m_ObservedTypes = new Dictionary<Type, Dictionary<ChangeAction, EventHandler>>();
public static void Observe(Type type)
{
if (m_ObservedTypes.ContainsKey(type) == false)
{
m_ObservedTypes.Add(type, new Dictionary<ChangeAction, EventHandler>());
EventHandler eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Insert, eventHandler);
eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Update, eventHandler);
eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Delete, eventHandler);
}
}
public static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> Events
{
get { return m_ObservedTypes; }
}
}
public class MyClass
{
public MyClass()
{
BaseDataContext.Events[typeof(User)][ChangeAction.Update] += new EventHandler(OnUserUpdate);
}
public void OnUserUpdated(object sender, EventArgs args)
{
//do something
}
}
De penser à ce qui m'a fait réaliser que je ne comprends pas vraiment ce qui se passe sous l'auge avec des événements - et j'aimerais comprendre 🙂
- Voir aussi ma réponse stackoverflow.com/questions/2598170/...
Vous devez vous connecter pour publier un commentaire.
J'ai écrit ce jusqu'à une bonne quantité de détails dans un article, mais voici le résumé, en supposant que vous êtes raisonnablement heureux avec les délégués eux-mêmes:
Le terrain, comme les événements, il y a une synchronisation mais sinon, l'ajout/suppression de simplement appeler Délégué.Combiner/Supprimer pour modifier la valeur de l'auto-champ généré. Deux de ces opérations, de céder à la sauvegarde de champ - rappelez-vous que les délégués sont immuables. En d'autres termes, le code généré automatiquement est très bien comme cela:
La valeur initiale du champ généré dans votre cas est
null
- et il y aura toujours desnull
encore si tous les abonnés sont supprimés, comme c'est le comportement de Délégué.Retirez.Si vous voulez un "no-op" gestionnaire de s'abonner à votre événement, afin d'éviter la nullité de vérifier, vous pouvez le faire:
La
delegate {}
est juste une méthode anonyme qui ne se soucie pas de ses paramètres et ne fait rien.Si il ya quelque chose qui est toujours pas clair, veuillez demander et je vais essayer de vous aider!
public EventHandler<EventArgs> ElementAddedEvent = delegate {};
Ce on dirait que je suis l'affectation d'une instance de délégué pour moi. En outre__ElementAddedEvent = Delegate.Remove(__ElementAddedEvent, value);
ce aussi le type de l'attribution d'une instance de délégué pour moi. Pourriez-vous expliquer la déclaration. Je suis un débutant difficile à obtenir.Sous le capot, les événements sont juste des délégués spéciaux conventions d'appel. (Par exemple, vous n'avez pas à vérifier la nullité avant de déclencher un événement.)
En pseudo-code, un Événement.Invoke() se décompose comme ceci:
Si L'Événement A Auditeurs
Appel chaque auditeur de manière synchrone sur ce fil dans un ordre arbitraire.
Depuis les événements sont de multidiffusion, ils vont avoir zéro, un ou plusieurs auditeurs, tenue dans une collection. Le CLR boucle à travers eux, l'appel de chaque dans un ordre arbitraire.
Un gros bémol à retenir est que les gestionnaires d'événements sont exécutés dans le même thread que l'événement est déclenché dans. C'est une commune mentale erreur de penser que la reproduction d'un nouveau thread. Ils ne le font pas.