2016-03-02 3 views
1

Suivre jusqu'à ma question here:Comment puis-je extraire la "vraie" cible d'un gestionnaire d'événements qui a été défini anonymement?

Selon un commentaire fait -

Le compilateur crée un membre de la classe avec un nom fictif et il se fixe comme vous attacherait une méthode déclarée.

Je ne comprends pas bien ce que cela signifie mais je peux vérifier que si, au lieu de dire

Foo.Bar += (S, E) => { /*Code Goes Here*/ } 

Je dis au lieu

Foo.Bar += FooBar; 

private void FooBar(object sender, EventArgs e){ 
    /*Code Goes Here*/ 
} 

puis Event.Target passe de WhatIsThis.App.<>c à WhatIsThis.App.

C'est génial mais je ne peux pas garantir que j'écrirai toujours une méthode à attacher à un gestionnaire d'événements.

Dans les cas où j'utilise une méthode anonyme, est-il un moyen d'extraire la cible réelle, ou suis-je simplement inclassable en utilisant des méthodes définies (je veux dire, je peux vivre avec ça, je suppose, mais s'il y a une sorcellerie high-tech que je peux utiliser pour extraire la vraie cible, alors je suis tout à fait pour ça).

+0

Quel est le problème avec l'utilisation du premier paramètre ('sender')? – spender

+0

@spender Le problème est que dans certains cas, l'expéditeur sera nul. L'expéditeur n'est pas impliqué pour être la cible de toute façon. Ce serait comme envoyer un paquet de moi-même, non? – Will

+0

... était juste en train de rattraper votre précédente question ... ignorer le commentaire précédent. – spender

Répondre

4

ne comprennent pas pleinement ce que cela signifie

Fixons votre compréhension. Supposons que vous ayez:

class C 
{ 
    int x; 
    void M(int y) 
    { 
    int z = GetZ(); 
    Func<int, int> f = q => q + x + y + z; 
    ... 

f est un délégué. Il a un récepteur et une méthode qui est une méthode du récepteur. (Notez, ce n'est pas vraiment une exigence stricte, mais le cas de coin est obscur pour nos fins aujourd'hui.)

Quel type est le récepteur qui a cette méthode? Cela peut-il être C, avec le récepteur égal à this?

Non pourquoi pas? Parce que alors, comment pouvons-nous garder la trace de la valeur de y et z? Il pourrait y avoir une valeur différente pour chaque appel de M, donc le destinataire ne peut pas être this.

Ce que le compilateur ne génère est une nouvelle classe:

class C 
{ 
    int x; 
    class Locals 
    { 
    public C __this; 
    public int y; 
    public int z; 
    public int A(int q) { return q + __this.x + y + z; } 
    } 

    void M(int y) 
    { 
    Locals locals = new Locals(); 
    locals.__this = this; 
    locals.y = y; 
    locals.z = GetZ(); 
    Func<int, int> f = locals.A; 
    ... 

Alors, quel est le récepteur? la valeur des habitants. Quelle est la méthode? A.

Bien sûr, les Locaux et A sont donnés des noms fous de sorte que vous ne pouvez pas les appeler par accident.

Dans les cas où j'utilise une méthode anonyme, est-il un moyen d'extraire la cible réelle

Vous extrayez le récepteur réel, je vous le promets.

« travaille sur une extension pour faire des choses avec des gestionnaires d'événements et je dois être en mesure de discerner ce qui est

une cible de gestionnaires d'événements S'il vous plaît ne pas le faire. Le destinataire d'un gestionnaire d'événements est un détail d'implémentation du code fourni par le gestionnaire. Ce n'est pas là pour prendre des décisions. Les compilateurs ont tout à fait le droit de faire tout ce qu'ils veulent quand ils génèrent un récepteur pour un gestionnaire d'événement, ce qu'ils font. Considérez ce qui se passe si le gestionnaire d'événements a été créé à l'intérieur d'un bloc d'itérateur ou d'une méthode asynchrone, par exemple. Ou l'événement est souscrit par un code d'extensions réactives qui applique des opérations de séquence à l'événement. Encore une fois, le compilateur générera des classes partout. Vous ne pouvez pas compter sur le fait que la classe soit quelque chose de "sensé". La seule chose sur laquelle vous pouvez compter est: l'abonné souhaitait que la méthode donnée soit appelée quand quelque chose se produisait. C'est le contrat que vous devez obéir; n'essayez pas de deviner l'abonné.

+0

Ok merci de m'avoir aidé à devenir moins ignorant. Je devrais spécifier - la raison pour laquelle je veux savoir quelle est la cible ('ISynchronizeInvoke' vs' DispatcherObject') est parce que je veux être en mesure de gérer gracieusement tout le thread sans exploser les choses (donc pouvoir appeler 'ISynchronizeInvoke.InvokeRequred 'et' ISynchronizeInvoke.Invoke (...) 'ainsi que' DispatcherObject.Dispatcher.CheckAccess() 'et' DispatcherObject.Dispatcher.Invoke (...) 'avec une relative impunité irait un long chemin vers m'aider avec cette – Will

+0

@Will: Si le contrat que l'observateur et l'observable ont entre eux est que l'observable va chercher un événement sur un contexte de thread autre que celui dans lequel l'observateur a donné le gestionnaire à l'observable alors les auteurs de ces deux classes Il serait surprenant que le gestionnaire soit rappelé dans un contexte différent de celui dans lequel le gestionnaire a été fourni. –