2010-10-12 25 views
54

Necesito implementar una propiedad de solo lectura en mi tipo. Además, el valor de esta propiedad se establecerá en el constructor y no se va a modificar (estoy escribiendo una clase que expone comandos UI enrutados personalizados para WPF, pero no importa).Cómo implementar una propiedad de solo lectura

Veo dos maneras de hacerlo:

  1. class MyClass 
    { 
        public readonly object MyProperty = new object(); 
    } 
    
  2. class MyClass 
    { 
        private readonly object my_property = new object(); 
        public object MyProperty { get { return my_property; } } 
    } 
    

Con todos estos errores FxCop diciendo que yo no debería tener variables miembro públicas, parece que el segundo es la forma correcta de hacerlo. ¿Correcto?

¿Hay alguna diferencia entre una propiedad para obtener solo y un miembro de solo lectura en este caso?

Agradecería cualquier comentario/consejo/etc.

+20

A veces me gustaría que la sintaxis de auto-propiedad incluyera un 'get; readonly set; 'opción. –

+0

Posible duplicado de [C#, inmutabilidad y campos públicos de solo lectura] (http://stackoverflow.com/questions/2249980/c-immutability-and-public-readonly-fields) – user

Respuesta

31

de versiones:
Creo que no hay mucha diferencia si sólo está interesado en la compatibilidad fuente.
Usar una propiedad es mejor para la compatibilidad binaria, ya que puede reemplazarla por una propiedad que tenga un setter sin romper el código compilado, según su biblioteca.

Convención:
Usted está siguiendo la convención. En casos como este, donde las diferencias entre las dos posibilidades son relativamente menores, seguir la convención es mejor. Un caso en el que podría volver a morderte es el código basado en la reflexión.Es posible que solo acepte propiedades y no campos, por ejemplo, un editor/visor de propiedades.

serialización
El cambio de campo a la propiedad probablemente romper un montón de serializadores. Y AFAIK XmlSerializer solo serializa propiedades públicas y no campos públicos.

El uso de un Autoproperty
Otra variación común es el uso de un autoproperty con un colocador privado. Si bien esto es corto y una propiedad, no hace cumplir la legibilidad. Entonces prefiero los otros.

campo Sólo lectura se selfdocumenting
Hay una ventaja del campo sin embargo:
Deja claro a simple vista en la interfaz pública que en realidad es inmutable (reflexión de restricción). Mientras que en el caso de una propiedad, solo puede ver que no puede cambiarlo, por lo que deberá consultar la documentación o la implementación.

Pero, para ser sincero, uso el primero bastante a menudo en el código de la aplicación porque soy perezoso. En las bibliotecas, normalmente soy más completo y sigo la convención.

C# 6.0 añade propiedades de sólo lectura de automóviles

public object MyProperty { get; } 

Por eso, cuando no es necesario para apoyar los compiladores de más edad se puede tener una propiedad realmente sólo lectura con código que es tan concisa como un campo de sólo lectura.

49

La segunda forma es la opción preferida.

private readonly int MyVal = 5; 

public int MyProp { get { return MyVal;} } 

Esto asegurará que MyVal sólo se puede asignar en la inicialización (que también se puede configurar en un constructor).

Como habrás notado, de esta manera no expones a un miembro interno, lo que te permite cambiar la implementación interna en el futuro.

+0

gracias. la primera opción también asegura lo mismo. ¿Cuál crees que es la razón por la cual esta es la opción preferida? – akonsu

+0

¿Hay alguna razón por la que no deberíamos usar 'public int MyProp {get; conjunto privado; } '? Sé que no es realmente solo, pero está muy cerca. –

+3

@Mike Hofer: como int está declarado como _readonly_, no puede cambiarlo fuera de un constructor. – Oded

4

Se prefiere el segundo método debido a la encapsulación. Ciertamente puede hacer que el campo de solo lectura sea público, pero eso va en contra de las expresiones idiomáticas de C# en las que tiene acceso de datos a través de propiedades y no campos.

El razonamiento detrás de esto es que la propiedad define una interfaz pública y si la implementación de respaldo a esa propiedad cambia, no termina rompiendo el resto del código porque la implementación está oculta detrás de una interfaz.

5

Estoy de acuerdo en que la segunda forma es preferible. La única razón real para esa preferencia es la preferencia general de que las clases .NET no tengan campos públicos. Sin embargo, si ese campo es de solo lectura, no puedo ver cómo habría otras objeciones reales aparte de la falta de coherencia con otras propiedades. La diferencia real entre un campo de solo lectura y una propiedad de solo obtención es que el campo de solo lectura proporciona una garantía de que su valor no cambiará durante la vida del objeto y que una propiedad de solo obtener acceso no lo hace.

+0

esta es una buena explicación. Gracias. – akonsu

8

Usted puede hacer esto:

public int Property { get { ... } private set { ... } } 
+4

Sí, puede hacerlo, pero con esta técnica solo garantiza que la propiedad no puede ser modificada por los consumidores de la clase, no que se mantendrá constante durante la vida útil del objeto. –

35

Con la introducción de C# 6 (en VS 2015), ahora puede tener get propiedades -sólo automáticas, en la que el campo respaldo implícito es readonly (es decir, los valores pueden ser asignados en el constructor, pero no en otra parte):

public string Name { get; } 

public Customer(string name) // Constructor 
{ 
    Name = name; 
} 

private void SomeFunction() 
{ 
    Name = "Something Else"; // Compile-time error 
} 

Y ahora también puede inicializar propiedades (con o sin un regulador) en línea:

public string Name { get; } = "Boris"; 

Volviendo a la cuestión, esto le da las ventajas de la opción 2 (miembro del público es una propiedad, no un campo) con la brevedad de la opción 1.

Desafortunadamente, no proporciona una garantía de inmutabilidad a nivel de la interfaz pública (como en el punto de @CódigosInChaos sobre auto-documentación), porque para un consumidor de la clase, no tener incubadora es indistinguible de tener un organismo privado.

+0

Buena información sobre la nueva sintaxis, sin embargo, puede reflejar y activar un setter privado y/o cargar un valor en un campo de respaldo (sin importar los modificadores de acceso). También es posible distinguir entre un setter privado y la falta de un setter en Tiempo de ejecución usando reflexión. –

+1

@Shaun: buen punto: ¡hay * muchas * cosas que puedes hacer con la reflexión! Varias de las posibilidades probablemente vayan en contra de la intención del programador original o incluso de los diseñadores del lenguaje, pero ¿está usted diciendo que los campos 'readonly' pueden alterarse usando la reflexión (no sé la respuesta, pero parece problemático)? –

+2

No estaba diciendo eso en particular, no, pero la respuesta es: Sí ... puedes. https://gist.github.com/wilson0x4d/a053c0fd57892d357b2c Si crees que eso es problemático, solo espera a que aprendas que cada sistema operativo en el planeta tiene un mecanismo en el lugar donde un proceso puede leer/escribir la memoria de cualquier otro proceso (dado suficiente privilegio de ejecución, es decir). Esta es la razón por la que ningún sistema basado en software puede ser verdaderamente seguro, pero, estoy divagando, esto no tiene mucho que ver con la pregunta original :) ¡incluso si es interesante! –

Cuestiones relacionadas