2010-05-25 14 views
19

Duplicar posible:
Convention question: When do you use a Getter/Setter function rather than using a Propertycaptadores y definidores deben y no deben hacer

me he encontrado un montón de opiniones diferentes sobre los captadores y definidores últimamente, por lo que pensé Debería convertirlo en su propia pregunta.

A previous question mío recibió un comentario inmediato (más tarde eliminado) que establece setters no debería tener ningún efecto secundario, y un método SetProperty sería una mejor opción.

De hecho, esto parece ser Microsoft's opinion también. Sin embargo, sus propiedades suelen generar eventos, como Resized cuando se establece la propiedad Width o Height de un formulario. OwenP también establece que "no debe permitir que una propiedad genere excepciones, las propiedades no deberían tener efectos secundarios, el orden no debería importar y las propiedades deberían regresar con relativa rapidez".

Sin embargo, Michael Stum indica que deben producirse excepciones al validar los datos dentro de un setter. Si su incubadora no lanza una excepción, ¿cómo podría usted efectivamente validar los datos, como sugieren muchas de las respuestas a this question?

¿Qué ocurre cuando necesita plantear un evento, como casi todos los de Control de Microsoft? ¿No estás entonces a merced de quien se suscribió a tu evento? Si su manejador realiza una cantidad masiva de información, o arroja un error en sí mismo, ¿qué le sucede a su incubadora?

Finalmente, ¿qué hay de lazy loading dentro del captador? Esto también podría violar las pautas anteriores.

¿Qué se puede colocar en un getter o setter, y qué se debe guardar en los métodos de acceso solamente?

Editar:

Desde otro article en el MSDN:

Los métodos get y set son generalmente no es diferente de otros métodos. Pueden realizar cualquier lógica de programa, lanzar excepciones, anularse y declararse con cualquier modificador permitido por el lenguaje de programación. Tenga en cuenta, sin embargo, que las propiedades también pueden ser estáticas. Si una propiedad es estática, existen limitaciones sobre lo que pueden hacer los métodos get y set. Consulte su referencia de lenguaje de programación para más detalles.

+0

Leí esa pregunta, las respuestas, e incluso me vinculé a ella en mi propia pregunta. No vi nada sobre la generación de eventos, que creo que merece diferentes respuestas. – dlras2

+1

@Rowland: creo que es lo suficientemente específico como para ser diferente. –

+2

¿Quién votó para que esto se migrara a Superusuario? – ChrisF

Respuesta

15

Mi opinión:

  1. Si se espera una incubadora o captador por qué ser caro, no lo hacen de una propiedad, lo convierten en un método.

  2. Si configurar una propiedad desencadena eventos debido a cambios, esto está bien. ¿De qué otro modo permitirías que los oyentes reciban notificaciones de los cambios? Sin embargo, es posible que desee ofrecer un par BeginInit/EndInit para suprimir eventos hasta que se realicen todos los cambios. Normalmente, es responsabilidad del controlador de eventos regresar rápidamente, pero si realmente no puede confiar en que lo haga, entonces puede querer señalar el evento en otro hilo.

  3. Si establecer una propiedad arroja excepciones sobre valores no válidos, también está bien. Esta es una forma razonable de señalar el problema cuando el valor es completamente incorrecto. En otros casos, configura un conjunto de propiedades y luego llama a un método que las usa para hacer algo, como establecer una conexión. Esto permitiría retrasar la validación y el manejo de errores hasta que se usen las propiedades, por lo que las propiedades no necesitarían arrojar nada.

  4. Acceder a una propiedad puede tener efectos secundarios siempre que no sean inesperados y no importen. Esto significa que una instancia de JIT en un getter está bien. Del mismo modo, establecer una bandera sucia para la instancia cada vez que se realiza un cambio está bien, ya que establece una propiedad relacionada, como un formato diferente para el mismo valor.

  5. Si hace algo en lugar de simplemente acceder a un valor, debe ser un método. El método son verbos, por lo que la creación de una conexión se haría mediante el método OpenConnection(), no una propiedad de conexión. Una propiedad de conexión se usaría para recuperar la conexión en uso o para vincular la instancia a otra conexión.

edición - añadió 5, cambió 2 y 3

1

estoy de acuerdo con la idea de que getters/ajustes no deben tener efectos secundarios, pero yo diría que no deben tener no efectos secundarios obvios

En cuanto a arrojar excepciones, si está configurando una propiedad con un valor no válido (en un sentido muy básico), entonces las excepciones de validación están bien. Sin embargo, si el colocador está ejecutando una serie completa de validación de reglas comerciales complicadas, o tratando de apagar y actualizar otros objetos, o cualquier otra cosa que pueda causar una excepción, entonces eso es malo. Pero este problema no es realmente un problema con la excepción en sí misma, sino más bien que el colocador se está apagando y realizando en secreto una gran cantidad de funciones que la persona que llama no esperaría (o no debería esperar).

Lo mismo con los eventos. Si un colocador está lanzando un evento diciendo que "esta propiedad cambió", entonces está bien, porque ese es un efecto secundario obvio. Pero si está desencadenando algún otro evento personalizado por lo que causa que algún tipo de código escondido se ejecute en otra parte del sistema, es malo.

Esta es la misma razón por la que evito la carga lenta en getters. De hecho, pueden facilitar las cosas la mayor parte del tiempo, pero pueden hacer que las cosas sean más confusas algunas veces, porque siempre termina siendo una lógica intrincada exactamente en el momento en que desea cargar los objetos secundarios. Por lo general, solo hay una línea más de código para cargar explícitamente los objetos secundarios cuando se está rellenando el objeto primario, y puede evitar mucha confusión sobre el estado del objeto. Pero este aspecto puede ser muy subjetivo, y mucho depende de la situación.

+0

Evitar la pereza puede tener costos sustanciales de rendimiento, así que no creo que sea una buena idea en general. –

+1

@Steven Sundit: Sí, es una compensación, y depende de la situación. Si la precarga introduce costos de rendimiento sustancial, entonces busque la carga diferida o la carga más específica de la situación. Pero a menudo (y en mi experiencia, por lo general) ese no es el caso. –

+0

La precarga sin duda puede ser una opción adecuada, especialmente cuando es barata o de una sola vez. Cuando no es ninguno, entonces JIT se convierte en un movimiento forzado. –

0

Siempre he encontrado que el enfoque conservador es el mejor, al trabajar en C# de todos modos. Debido a que las propiedades son sintácticamente iguales a los campos, deberían funcionar como campos: sin excepciones, sin validación, sin negocios graciosos. (De hecho, la mayoría de mis propiedades comienzan como campos simples, y no se convierten en propiedades hasta que sea absolutamente necesario.) La idea es que si ves algo que parece estar obteniendo o configurando un campo, entonces ES algo así como obtener o establecer un campo, en términos de funcionalidad (no hay excepción), la eficiencia general (las variables de configuración no desencadenan una cascada de llamadas de delegado, por ejemplo) y el efecto en el estado del programa (establecer una variable establece esa variable, y doesn ' llamar a muchos delegados que podrían hacer casi cualquier cosa).

cosas sensibles para un conjunto de propiedades que ver incluyen el establecimiento de una bandera para indicar que ha habido un cambio:

set { 
    if(this.value!=value) { 
     this.changed=true; 
     this.value=value; 
    } 
} 

Tal vez en realidad establecer un valor en otro objeto, por ejemplo:

set { this.otherObject.value=value; } 

Tal vez desenrede la entrada un poco, para simplificar el código interno de la clase:

set { 
    this.isValid=(value&Flags.IsValid)!=0; 
    this.setting=value&Flags.SettingMask; 
} 

(O Por supuesto, en estos dos últimos casos, la función get bien podría hacer lo contrario.)

Si algo más complicado tiene que pasar, en particular llamar delegados, o realizar validación, o lanzar excepciones, entonces mi opinión es que una la función es mejor. (Muy a menudo, mis campos se convierten en propiedades con get y set, y luego terminan como una propiedad get y una función set.) De forma similar para los getters; si devuelve una referencia a algo, no es un problema, pero si está creando un objeto grande completamente nuevo y lo rellena cada vez que se lee la propiedad, no tanto.

+0

Si trabaja en C#, debe tener en cuenta WPF, que depende completamente de los cambios de propiedad que tengan el efecto secundario de señalar esos cambios. No veo cómo podemos seguir tu consejo sin paralizar nuestro código. –

+0

Cuando dices "el efecto secundario de señalar esos cambios", ¿te refieres a plantear un evento? ¿O está diciendo que 'if (this.value! = Value) return;' sería una mala idea? No he trabajado con WPF. (Aunque sí programa en C#.) – dlras2

+0

@Cyclotis: Bueno, esto se aplica a algo más que WPF, pero WPF hace un uso particularmente obvio de la notificación de cambio de propiedad. También encontrará ejemplos en muchos lugares donde se utiliza el enlace de datos. Si no nos permiten desencadenar eventos cuando hay un cambio, ¿qué tenemos en su lugar? ¿Votación? –

Cuestiones relacionadas