2011-11-15 2 views
6

Je me demande si je fais quelque chose comme ceci:événements C# et des méthodes de classe

class A 
{ 
    public MethodA() 
    { 
    } 
    public MethodB() 
    { 
     ExternalObject.Click += this.MethodA; 
    } 
    public MethodC() 
    { 
     ExternalObject.Click -= this.MethodA; 
    } 
} 

A a = new A(); 
a.MethodB(); 
a.MethodC(); 

Est-ce que ça va fonctionner? Par "travail" je veux dire - MethodA sera-t-il désinscrit de l'événement ExternalObject.Click?

et d'autres questions connexes:

Que se passe dans les coulisses quand une méthode d'instance est utilisé au lieu d'instance de délégué? (comme ci-dessus)

Est-ce que cela provoque la création implicite d'un délégué?

Comment l'opérateur -= effectue-t-il une comparaison entre délégués - par référence ou peut-être que quelque chose de plus sophistiqué se produit?

Répondre

8

Oui, cela fonctionnera comme vous le voulez.

La comparaison ne se fait pas par référence, c'est par valeur, ce qui signifie que vous pouvez vous désabonner d'un autre délégué, tant qu'il pointe vers la même méthode sur le même objet.

En d'autres termes, cela fonctionne très bien:

var delegate1 = new ExternalObjectClickEventHandler(MethodA); 
var delegate2 = new ExternalObjectClickEventHandler(MethodA); 
ExternalObject.Click += delegate1; 
ExternalObject.Click -= delegate2; 

Les méthodes anonymes sont différentes cependant, vous ne pouvez pas le faire:

public MethodB() 
{ 
    ExternalObject.Click +=() => { return 10; }; 
} 

public MethodC() 
{ 
    ExternalObject.Click -=() => { return 10; }; 
} 

Bien que les méthodes contiennent le même code, ils sont considérés comme différent, et donc cela ne fonctionnera pas, c'est-à MethodC ne désinscrira pas le délégué que vous avez ajouté dans MethodB.

Pour résoudre ce problème, vous devez stocker le délégué entre les invocations, comme ceci:

private ExternalObjectClickEventHandler _ClickEventHandler; 
public MethodB() 
{ 
    _ClickEventHandler =() => { return 10; }; 
    ExternalObject.Click += _ClickEventHandler; 
} 

public MethodC() 
{ 
    ExternalObject.Click -= _ClickEventHandler; 
} 

Mais le code que vous montriez, travaillerez.

Quant à votre question ce qui se passe dans les coulisses, est que les deux lignes de code sont identiques en ce qui concerne le code généré suivant:

ExternalObject.Click += MethodA; 
ExternalObject.Click += new ExternalObjectClickEventHandler(MethodA); 

Le second code est ce qui est généré à partir du premier (en supposant le type de l'événement est comme indiqué.)

La première syntaxe a été (à un certain point) ajoutée en tant que "sucre syntaxique" qui est traduit par le compilateur comme si vous aviez écrit la deuxième syntaxe. Notez que cela ne se produit que si le compilé peut trouver le bon type 100%. J'ai vu quelques cas (dont je ne me souviens pas maintenant) où vous deviez utiliser la syntaxe complète parce que le compilateur ne pouvait pas comprendre ce que vous vouliez dire. En particulier, les surcharges de méthodes et les génériques peuvent le rendre confus à cet égard.

+0

Merci pour votre réponse complète. – kubal5003

3

Oui, MethodA sera désabonné. A propos de la deuxième question, je ne suis pas sûr à 100%, mais je pense que = this.MethodA se convertit en un délégué en arrière-plan.

+0

+1. 'this.MethodA' sera implicitement converti en un délégué. – kol

Questions connexes