2010-08-17 17 views
9

Estoy usando C# 3.0. Siguiendo el patrón de eventos estándar que tengo:¿Mi clase debe suscribirse a sus propios eventos públicos?

public event EventHandler<EventArgs> SomeEventHappens; 

    protected virtual void OnSomeEventHappens(EventArgs e) 
    { 
     if (SomeEventHappens != null) 
     { 
      SomeEventHappens(this, e); 
     } 
    } 

    private object _someProperty; 

    public object SomeProperty 
    { 
     get 
     { 
      return _someProperty; 
     } 
     private set 
     { 
      if (_someProperty == value) 
      { 
       return; 
      } 
      OnSomeEventHappens(EventArgs.Empty); 
      _someProperty = value; 
     } 
    } 

Dentro de mi misma clase me gustaría tomar algunas acciones cuando SomeProperty cambios. La forma en que lo veo Tengo 3 alternativas:

1) Hacer cosas dentro de mi SomeProperty setter. Algo me frota en el camino equivocado al hacer esto, ya que trato de suscribirme a la filosofía de que todo debería hacer una cosa y hacerlo bien. Arrebatar cosas en un setter parece ir en contra de eso, o al menos tiene la propensión a.

2) Haz cosas en OnSomeEventHappens. De nuevo, parece ir un poco en contra de mantener esto en pedazos simples. Además, si se anula este método, podría perder funcionalidad si el implementador no llama al método base.

3) Haga que la clase se suscriba a SomeEventHappens. Para mí, esta parece ser la elección correcta en lo que respecta a la encapsulación, y parece bastante limpia. Nuevamente, posibles repercusiones si se anula el OnSomeEventHappens.

¿Tal vez hay algo más elegante? No puedo decidir entre la opción 2 y 3, y tengo curiosidad sobre cuáles son las mejores prácticas. Quizás el lugar más seguro esté en el establecimiento de la propiedad después de todo.

¿Pensamientos?

Actualización: Gracias por los buenos comentarios y respuestas a continuación. He aprendido que está "bien" tener una clase suscribirse a sus propios eventos, aunque en mi caso me inclino a no hacerlo debido a la sobrecarga. He pensado en el comportamiento de posibles usuarios de mis métodos virtuales y qué es exactamente lo que quiero que suceda.

En mi caso del mundo real, realmente no quiero que los eventos se levanten sin que se establezca la propiedad. Como las respuestas a continuación han guiado mi proceso de pensamiento, creo que puedo ir con la opción 1, debido a la menor sobrecarga, a la reducción del riesgo de un comportamiento inadecuado por parte de los herederos, y generalmente tiene más sentido para mí. ¡Gracias de nuevo!

Respuesta

2

Si llama SomeEventHappens y OnSomeEventHappens desde una ubicación común (el procedimiento de propiedad u otra función), entonces no tiene que preocuparse de que los overriders descuiden el evento. Preferiría anular una función en lugar de manejar eventos porque hay menos sobrecarga.

+0

Elegí esta respuesta porque era la explicación más cercana a lo que terminé haciendo. Aprendí mucho de las otras respuestas. ¡Gracias! –

1

¿Va a siempre desea realizar esta acción, o puede que desee suscribirse y darse de baja? En este último caso, la opción 3 es claramente una buena idea.

¿Es la acción que desea tomar el tipo de acción que otra clase puede tomar? De nuevo, eso se inclinaría hacia la opción 3.

¿La acción que desea realizar forma parte intrínseca de la configuración de la propiedad? Si es así, la acción 1 puede ser aconsejable.

La opción 3 suena como un buen acercamiento "ligero" para mí.

+0

En mi situación en el mundo real (no la versión demasiado simplificada anterior) no me gustaría suscribirme y cancelar la suscripción. La propiedad es en realidad una enumeración y cualquiera de una serie de eventos diferentes se genera según el valor enum que se establezca. Como estoy planteando el evento en el colocador, toda la información del evento está disponible para mí allí. En lo alto, puede ser más ligero no suscribirse a todos esos eventos y solo lidiar con eso en el setter. –

2

En frameworks de objetos fuera de .NET, un objeto que se suscribe a sus propios eventos está mal visto principalmente porque tales cosas llevan a referencias circulares que podrían mantener el objeto vivo indefinidamente. Esto no es un problema en.NET, pero aún me parece "extraño" que un objeto se toque a sí mismo de esta manera.

Si una clase siempre necesita saber cuándo ocurren cambios en la propiedad, su mejor opción es hacer el método OnSomeEventHappens virtual y anularlo en las clases descendientes que necesitan la información adicional. Está bien poner código en el método de activación de eventos. El método de activación de eventos está allí precisamente para que todos los que quieran lanzar ese evento tengan una manera uniforme de hacerlo.

Si solo ocasionalmente necesita ser informado de cuándo cambia la propiedad, entonces supongo que sería apropiado suscribirse y cancelar la suscripción al evento.

+0

Mi pensamiento inicial fue que posiblemente estaba mal visto que una clase se auto-suscribiera también. De algunas de las otras respuestas y la tuya, no parece ser un problema en .NET. Si pongo algo de lógica adicional en mi método virtual OnSomeEventHappens, debo dar el salto de la fe de que los overriders llamarán a la versión base en su reemplazo. Para mis propósitos, todavía estoy debatiendo si eso sería un problema o no. –

+1

La principal diferencia entre los virtuales y los eventos es que los eventos son/deberían ser sin contrato con poca o ninguna demanda sobre lo que deben hacer los controladores de eventos, mientras que los virtuales son intrínsecamente contractuales. Siempre es el caso que un método virtual debe documentarse para describir cuándo y cuándo los descendientes deben invocarlo al extender o anular el comportamiento. IOW, si sus overriders son buenos programadores, esto no debería ser una preocupación importante. Si sus overriders serán el público en general/idiotas al azar, entonces las fortificaciones pueden ser necesarias. – dthorpe

+0

¡Existe un 99% de posibilidades de que cualquier superviviente sea mi ser futuro, ya sea que eso me ponga en la categoría de buen programador o idiota al azar está en debate! :) –

1

Si posee el estado de su propio objeto, la captura de eventos me suena mal. Me gustaría ir con un método virtual por separado. No interfieras con tu evento y espera que los niños lo tomen. Tal vez esto sería algo así como:

private object _someProperty; 
    public object SomeProperty 
    { 
     get 
     { 
      return _someProperty; 
     } 
     private set 
     { 
      if (_someProperty != value) 
      { 
       OnSettingSomeProperty(_someProperty, value); 
       OnSomeEventHappens(EventArgs.Empty); 
       _someProperty = value; 
      } 
     } 
    } 

    protected virtual void OnSettingSomeProperty(object oldValue, object newValue) 
    { 
     // children can play here, validate and throw, etc. 
    } 
+0

Esto vuelve a inclinarse a la Opción 1. Aunque no creo que vaya a hacer que OnSettingSomeProperty sea virtual, probablemente sea privado, así que podría garantizar que no se perderá. Me importa menos el hecho de que se haya suscitado el evento que las condiciones que lo provocaron en primer lugar. –

+0

@jomtois, la intención de 'OnSettingSomeProperty' es permitir que los descendientes inyecten el comportamiento. Está claro lo que tienes pero no lo que quieres en tu publicación original. Quizás no esté satisfecho con la respuesta de alguien porque no ha definido 'Hacer las cosas ...' en su pregunta. – Marc

Cuestiones relacionadas