2008-10-15 10 views
19

Hay muchos consejos que indican que no debe exponer públicamente sus campos y, en su lugar, usar propiedades triviales. Lo veo más de & más.¿Alguna vez ha salvado su tocino de propiedades triviales?

Entiendo los argumentos, pero I don't think it's good advice in most cases.

¿Alguien tiene un ejemplo de una época en la que realmente importaba? Cuando escribir una propiedad trivial hizo posible algo importante en el futuro (o cuando dejar de usar uno los metió en problemas reales)?

EDIT: El argumento DataBinding es correcto, pero no muy interesante. Es un error en el código de enlace de datos que no aceptará campos públicos. Entonces, tenemos que escribir propiedades para evitar ese error, no porque las propiedades sean una opción de diseño de clase inteligente.

EDITAR: Para ser claros, estoy buscando ejemplos del mundo real, no teoría. Un momento en que realmente importaba.

EDITAR: La capacidad de establecer un punto de interrupción en el colocador parece valiosa. Diseñar mi código para el depurador es desafortunado: prefiero que el depurador se vuelva más inteligente, pero dado el depurador que tenemos, tomaré esta habilidad. Buen material.

+0

en tu comentario a @JasonBunting te lamentas por los tipos inmutables y de solo lectura. Tengo curiosidad por qué no puede lograr esto con MyProperty {get; conjunto privado; }? –

+0

@Robert: Porque no obtengo la verificación gratuita de que mi implementación no está modificando el estado. –

+1

Si no confía en usted mismo, use un campo de respaldo y escriba pruebas unitarias. nombre de cadena privada de solo lectura; public string Nombre {get {return name; }} 'propiedad o indizador' ... No se puede asignar el nombre '- es de solo lectura –

Respuesta

25

Puede ser difícil hacer que el código funcione en un futuro incierto, pero eso no es excusa para ser flojo. Codificar una propiedad sobre un campo es una convención y es pragmático. Llámalo programación defensiva.

Otras personas también se quejarán de que hay un problema de velocidad, pero el JIT es lo suficientemente inteligente como para hacerlo tan rápido como exponer un campo público. Lo suficientemente rápido para que nunca lo note.

Algunas cosas no triviales que vienen a la mente

  1. Un campo público es totalmente pública, no se puede imponer sólo lectura o sólo escritura semántica
  2. Una propiedad puede tener que tienen diferentes get frente set accesibilidad (p. ej. public get, internal set)
  3. No puede anular un campo, pero puede tener propiedades virtuales.
  4. Su clase no tiene control sobre el campo público
  5. Su clase puede controlar la propiedad. Puede limitar la configuración al rango permitido de valores, marcar que se modificó el estado e incluso cargar el valor de forma perezosa.
  6. La semántica de reflexión difiere. Un campo público no es una propiedad.
  7. Sin enlace de datos, como otros señalan. (Es solo un error para usted. - Puedo entender por qué los diseñadores de marcos .net no admiten patrones que no están a favor.)
  8. No puede poner un campo en una interfaz, pero puede poner una propiedad en una interfaz.
  9. Su propiedad ni siquiera necesita almacenar datos. Puede crear una fachada y enviar a un objeto contenido.

Solo debe introducir 13 caracteres adicionales para su corrección. Eso apenas parece una generalidad especulativa. Hay una diferencia semántica, y si nada más, una propiedad tiene un significado semántico diferente y es mucho más flexible que un campo público.

public string Name { get; set; } 
public string name; 

sí recuerdo una vez cuando primero usando .net codifiqué algunas clases como sólo los campos, y luego tenía que tener como propiedades, por alguna razón, y fue una completa pérdida de tiempo cuando podía lo acabo de hacer bien la primera vez.

Entonces, ¿qué razones tiene para no siguiendo la convención? ¿Por qué sientes la necesidad de nadar aguas arriba? ¿Qué te ha salvado al no hacer esto?

+0

¡Esta es una excelente respuesta! Más completo que he encontrado en cualquier parte mientras investigaba el tema. – aleemb

+2

Me encantó esta frase: "Entonces, ¿qué razones tienes para no seguir las convenciones? ¿Por qué sientes la necesidad de nadar aguas arriba? ¿Qué te ha salvado al no hacer esto?" Le he estado preguntando a un compañero de trabajo exactamente lo mismo, ya que insiste en formatear su C# como si fuera un mainframe ANSI C de 1972. –

+0

Lo que gana es claridad: no garantiza ningún comportamiento, algo de velocidad (el JIT no es mágico) , la capacidad de marcar el campo de forma sencilla, métricas de cobertura de código más útiles. Considero que el argumento de la claridad y la simplicidad es extremadamente convincente a menos que haya motivos para pensar que necesita una de las características 1-9 que menciona, seguiría a YAGNI. ¡Mantenlo simple! –

10

Parte de la idea es que esas propiedades pueden no ser triviales en el futuro: si vincula el código externo a un campo y luego desea envolverlo en una propiedad, todo el código dependiente tendría que cambiar, y usted Es posible que no pueda hacer eso, especialmente en el caso de que sea un diseñador de control o tenga librerías que no puede controlar, etc.

Sin mencionar que hay ciertas prácticas .NET que no le permitirán usar un campo - enlace de datos en particular.

Estoy seguro de que hay otras buenas razones también. ¿Por qué te importa? Use una propiedad automática y termine con esto. Parece algo que no vale la pena preocuparse por mí ...

+0

El enlace de datos está roto. Sucks. Supongo que tengo que lidiar con eso. Las propiedades automáticas no permiten 'readonly', lo que hace que los tipos inmutables sean un poco más difíciles. Me gustaría que mis propiedades permanezcan como diciendo "¡Cuidado! ¡Esto no es solo información!" –

+0

Puede hacer una propiedad automática con un conjunto privado, lo que lo lleva a una parte del camino hasta allí. –

11

Yo solía pensar lo mismo, Jay. ¿Por qué utilizar una propiedad si solo está allí para proporcionar directa acceso a un miembro privado? Si puede describirlo como una propiedad automática, tener una propiedad en vez de un campo parece algo tonto. Incluso si alguna vez necesita cambiar la implementación, siempre podría refactorizarse en una propiedad real más adelante y cualquier código dependiente funcionaría, ¿verdad? Bueno, tal vez no.

Verá, recientemente he visto la luz en propiedades triviales, por lo que quizás ahora pueda ayudarlo a hacer lo mismo.

Lo que finalmente me convenció fue el punto bastante obvio (en retrospectiva) que las propiedades en .Net son sólo azúcar sintáctico para los métodos get y set, y esos métodos tienen un nombre diferente de la propiedad en sí. El código en el mismo ensamblado seguirá funcionando, porque de todos modos tiene que volver a compilarlo al mismo tiempo. Pero cualquier código en un ensamblaje diferente que enlace al suyo fallará si refactoriza un campo a una propiedad, a menos que se vuelva a compilar contra su nueva versión al mismo tiempo. Si es una propiedad desde el principio, todo sigue siendo bueno.

+1

¿Puedes reconstruir los otros ensamblajes? Si es así, entonces no tienes un problema. Si no, tu problema es mucho más grande. http://stackoverflow.com/questions/174198/c35-automatic-properties-why-not-access-the-field-directly#205567 –

+0

Si su código es una biblioteca de clase comercial y realiza el cambio de campo público a propiedad , podrías REALMENTE irritar a tus clientes. – BlackWasp

+0

@BlackWasp: Esa es la teoría, pero ¿alguna vez realmente has necesitado hacer eso? Y no es necesario para hacer otros cambios de ruptura? Cuando la compatibilidad binaria era un requisito? –

1

Una vez tuve campos que quería exponer desde una ventana del proyecto que permitía las estadísticas para el programa (TotalItems y SuccessfulItems).

Más tarde decidí mostrar las estadísticas en el formulario y pude agregar una llamada en el colocador que actualizó la pantalla cuando la propiedad cambió.

13

He tenido una propiedad trivial, sálvame un par de veces al depurar. .Net no admite el concepto de punto de interrupción de datos (lectura o escritura). Ocasionalmente, al depurar un escenario muy complejo, era importante rastrear las lecturas/escrituras en una propiedad en particular. Esto es fácil con una propiedad pero imposible con un campo.

Si no está trabajando en un entorno de producción, es fácil refactorizar un campo -> propiedad con el fin de depuración. Ocasionalmente, se topan con errores que solo se reproducen en un entorno de producción que es difícil de parchar con un nuevo binario. Una propiedad puede salvarte aquí.

Sin embargo, es un escenario bastante limitado.

+2

Estaba publicando un punto similar. Te conseguiré la próxima vez, Gadget. –

+0

Eso me dio una buena risa :) – JaredPar

+0

+1 Nos ha tocado este. –

3

Es mucho más fácil depurar un problema relacionado con un campo si está envuelto por un descriptor de acceso a la propiedad. La colocación de puntos de interrupción en el acceso puede ayudar bastante rápidamente a encontrar la reentrada y otros problemas que de otro modo podrían no detectarse. Al ordenar todo acceso al campo a través de un descriptor de acceso, puede determinar exactamente quién está cambiando qué y cuándo.

2

En .NET, desde mi entender, no se puede enlazar con datos a campos públicos; pero solo a las propiedades. Por lo tanto, si desea hacer un enlace de datos, no tiene otra opción.

+0

Sí, DataBinding tiene ese error. –

+1

¿Error? ¿Estás seguro? – BlackWasp

+2

Para la vinculación de datos, normalmente también desea la notificación de actualización (INotifyPropertyChanged) por lo que se necesita una propiedad para plantear el evento. –

1

Obviamente, si no está creando una biblioteca de clases compartida, y no está utilizando DataBinding, el uso de un campo no le causará ningún problema.

Pero si va a crear una biblioteca de clases compartidas, serías mi humilde opinión tonto como para hacer otra cosa que seguir las directrices, para los habituales tres razones:

  • consumidores de la biblioteca de clase compartida puede querer para usar DataBinding.

  • consumidores de su clase compartida pueden querer compatibilidad binaria, lo que no es posible si cambia de un campo a una propiedad.

  • el principal de menor sorpresa implica que debe ser coherente con otras bibliotecas de clases compartidas, incluido el propio .NET Framework.

+0

RE: compatibilidad binaria: creo que las personas no lo necesitan tanto como dicen, y que las propiedades de tirival no son suficientes. Ver: http://stackoverflow.com/questions/174198/c35-automatic-properties-why-not-access-the-field-directly#205567 –

+0

No es solo compatibilidad binaria, también es compatibilidad de origen. –

0

En mi humilde opinión, no existe una propiedad trivial como la gente los ha estado llamando. A través del modo en que cosas como el trabajo de enlace de datos, Microsoft ha implicado que cualquier bit de datos que sea parte de la interfaz pública de un objeto debería ser una propiedad. No creo que quisieran decir que era simplemente una convención como lo es en algunos otros idiomas donde la sintaxis de la propiedad es más acerca de la convención y la conveniencia.

Una pregunta más interesante puede ser: "¿Cuándo debería usar un campo público en lugar de una propiedad", o "¿Cuándo ha guardado su tocino un campo público en lugar de una propiedad pública?"

+0

Creo que Microsoft cometió un error en las API de reflexión, por lo que es fácil reflejar solo las propiedades, pero no las propiedades + campos juntos. Ese error ha influido en el diseño de muchos otros sistemas, y ahora estamos atrapados con eso. –

+0

Jay, entiendo totalmente lo que dices. He programado en otros idiomas para que pueda ver su punto desde un punto de vista independiente del idioma. Sin embargo, este lenguaje funciona de la manera en que Microsoft lo diseñó para funcionar, no lo que tiene sentido para usted o para mí. –

10

Responderé a su pregunta con otra: ¿alguna vez se ha beneficiado realmente al no hacer públicos todos sus tipos y miembros? Sospecho que no he prevenido ningún error directamente al hacerlo. Sin embargo, he encapsulado mis tipos correctamente, solo exponiendo lo que se debe exponer. Las propiedades son similares: un buen diseño más que cualquier otra cosa. Pienso en las propiedades como conceptualmente diferentes de los campos; son parte del contrato en lugar de ser parte fundamental de la implementación. Pensar en ellos como propiedades en lugar de campos me ayuda a pensar más claramente sobre mi diseño, lo que lleva a un mejor código.

Ah, y me he beneficiado ocasionalmente por no haber roto la compatibilidad de la fuente, pudiendo establecer puntos de interrupción, acceso de registro, etc.

+0

Buena respuesta. Creo que me he beneficiado de la codificación de la forma en que lo hago, pero definitivamente hay espacio para desafiar de esa manera y para mejorar. Lamentablemente, creo que es demasiado complejo como para descubrir un hilo de comentarios de Stack Overflow. –

+0

Discurso adicional de Jon: http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx – aleemb

0

Los campos que son de tipos de estructura permiten el acceso directo a los miembros de los mismos, mientras que las propiedades de dichos tipos no. En consecuencia, si Thing.Boz fuera un campo de tipo Point, el código que desea modificar su valor X podría simplemente decir Thing.Boz.X += 5;; si Thing.Boz fuera una propiedad mutable, sería necesario usar var tmp = Thing.Boz; tmp.X += 5; Thing.Boz = tmp;. La capacidad de escribir las cosas más limpiamente con el campo expuesto es a menudo, pero no siempre, una bendición.

Si siempre será posible que Boz sea un campo, modificar sus miembros directamente será más limpio, más rápido y mejor que copiarlo a una variable temporal, modificarlo y copiarlo de nuevo.Si el tipo de Boz expone sus campos mutables directamente (como deberían ser las estructuras) en lugar de envolverlos en envoltorios triviales, también será posible usar cosas como los métodos Interlocked, algo que es simplemente imposible con las propiedades. En realidad, solo hay una desventaja para usar los campos de esa manera: si alguna vez es necesario reemplazar el campo con una propiedad, se romperá el código que se basa en lo que es un campo, y puede ser difícil de solucionar.

En pocas palabras, afirmaría que, en los casos en que uno no está preocupado por cambiar versiones diferentes de código sin tener que recompilar consumidores, el mayor efecto de usar propiedades en lugar de campos es evitar que los consumidores de el código de escribir código que aprovecharía (y se basaría) en la semántica de los campos expuestos que son de tipos de estructura.

Por cierto, una alternativa a exponer un campo de un tipo de estructura sería exponer un método ActOnXXX. Por ejemplo:

delegate void ActionByRef<T1>(ref T1 p1); 
delegate void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2); 
delegate void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3); 
// Method within the type that defines property `Boz` 
void ActOnBoz<T1>(ActionByRef<Point, T1> proc, ref T1 p1) 
{ 
    proc(ref _Boz, ref p1); // _Boz is the private backing field 
} 

Código, que quería añadir un poco variable local q a Thing.Boz.X podría llamar Thing.ActOnBoz((ref Point pt, ref int x) => {pt.X += x;}, ref q); y tiene la acción realizada directamente en Thing._Boz, a pesar de que el campo no está expuesto.

Cuestiones relacionadas