2009-10-05 5 views
1

Faire du développement à base de composants, je me retrouve à faire ce assez souvent:Quelle est la façon la plus élégante d'échanger les événements lors de la création d'une propriété?

public class SomeClass 
{ 
    SomeOtherClass foo; 

    public SomeOtherClass Foo 
    { 
     get { return foo; } 
     set { 
      if (value != foo) { 
       if (value != null) { 
        // subscribe to some events 
        value.SomeEvent += foo_SomeEvent; 
       } 

       if (foo != null) { 
        // unsubscribe from subscribed events 
        foo.SomeEvent -= foo_SomeEvent; 
       } 

       foo = value; 
      } 
     } 
    } 

    void foo_SomeEvent(object sender, EventArgs e) 
    { 
     // do stuff 
    } 
} 

est-il un moyen plus élégant de faire cet événement « transfert de sortie »?

(Bien sûr, la question pourrait être évitée si foo était immuable, mais je ne voudrais pas obtenir un soutien de concepteur visuel.)

Répondre

5

Je ne pense que votre implémentation actuelle est tout à fait acceptable. C'est très clair et facile à suivre.


Si vous voulez raccourcir le code, puisque vous faites cela beaucoup, vous pourriez faire une méthode qui le fait:

private void SwapEventHandler<T>(T a, T b, Action<T> subscribe, Action<T> unsubscribe) 
    where T : class 
{ 
    if (a != null) 
     subscribe(a); 
    if (b != null) 
     unsubscribe(b); 
} 

Vous pouvez alors écrire:

if (value != foo) 
{ 
    SwapEventHandler(value,foo, (o) => o.SomeEvent += foo_SomeEvent, (o) => o.SomeEvent -= foo_SomeEvent); 
    foo = value; 
} 
+0

Parfois, je me retrouve dupliquer ce code plusieurs fois dans une classe, et il commence semblant comme beaucoup d'ennuis pour une opération simple. Eh bien ... –

+0

Ouais, c'est le genre de cas où les macros C++ me manquent ... –

+0

Edité pour vous montrer une version plus courte en utilisant lambdas –

1

Ce que vous faites est très bien, mais je préfèreraient généralement la convention de désabonnement anciens gestionnaires d'événements avant vous inscrivant les nouvelles, pour éviter tout « chevauchement » des où les deux objets pourraient essayer de gérer le même événement si elle a tiré d'un autre fil entre les appels. Pour une amélioration marginale, vous pouvez vous passer d'accolades inutiles pour rendre le code plus compact et plus "ordonné" (où "plus propre" est dans l'œil du spectateur).

 
set 
{ 
    if (value != foo) 
    { 
     if (foo != null) 
      foo.SomeEvent -= foo_SomeEvent; 
     if (value != null) 
      value.SomeEvent += foo_SomeEvent; 

     foo = value; 
    } 
} 

Si vous le rendre illégal d'utiliser des références null (par exemple en utilisant une référence à un « Null Foo objet » au lieu d'un nul), alors vous pouvez passer des ifs entièrement:

 
set 
{ 
    if (value != foo) 
    { 
     foo.SomeEvent -= foo_SomeEvent; 
     value.SomeEvent += foo_SomeEvent; 
     foo = value; 
    } 
} 

dans certains cas où vous avez beaucoup de propriétés de travail avec des objets/événements similaires, vous pourriez aussi mettre en œuvre le code d'échange dans une méthode d'assistance (générique) afin que vous ayez la mise en œuvre en un seul endroit et vos propriétés tout simplement appeler une méthode d'assistance partagée. Ce ne serait bénéfique si vous pouvez partager une mise en œuvre de nombreuses propriétés que:

 
set 
{ 
    Helpers.SetValueAndResubscribeFooSomeEvent(ref foo, value); 
} 
0

Si vous ne savez pas quels événements a été enregistré sur l'événement, et que vous voulez effacer complètement, vous pouvez faire ce qui suit:

public class SomeOtherClass 
{ 
    public event EventHandler SomeEvent; 

    public void ClearSomeEvent() 
    { 
     foreach (EventHandler e in SomeEvent.GetInvocationList()) 
     { 
      SomeEvent -= e; 
     } 
    } 
} 

Et poseur de propriété SomeClass.Foo:

if (foo != null) 
{ 
    // unsubscribe from subscribed events      
    foo.ClearSomeEvent();     
} 

Si vous ne connaissez le délégué subcribed, vous êtes la solution actuelle est très bien.

+0

Je ne peux pas imaginer une situation commune où je voudrais me désinscrire des événements que je Je ne me suis pas abonné. Il semble vaincre le point de l'ensemble du mécanisme de souscription. –