2010-01-30 20 views
31

Esta pregunta surgió en los comentarios de this answer. La incapacidad de tener propiedades de solo lectura se propuso como una posible razón para usar campos en lugar de propiedades.¿Por qué las propiedades no pueden ser de solo lectura?

Por ejemplo:

class Rectangle 
{ 
    private readonly int _width; 
    private readonly int _height; 

    public Rectangle(int width, int height) 
    { 
     _width = width; 
     _height = height; 
    } 

    public int Width { get { return _width; } } 
    public int Height { get { return _height; } } 
} 

Pero ¿por qué no puedes hacer esto?

public int Width { get; readonly set; } 

Editar (clarificación): Se puede conseguir esta funcionalidad en el primer ejemplo. Pero ¿por qué no puedes usar la taquigrafía de propiedad implementada automáticamente para hacer lo mismo? También sería menos desordenado, ya que no tendría que acceder directamente a los campos en su constructor; todo acceso sería a través de la propiedad.

+7

Una mejor sintaxis sería 'public int Width {get; solo set de lectura; } ' – jason

+0

@Jason: Eso parece mejor, lo he editado para su versión. –

+3

@Jason: No sé, algo sobre el concepto de "setter de solo lectura" me parece muy extraño. Es fácil dar sentido aquí, en el contexto de esta pregunta, pero creo que si lo viera de la nada sería un momento de WTF. – Aaronaught

Respuesta

22

Porque el lenguaje no lo permite.

Esto puede parecer como una respuesta frívola: después de todo, los diseñadores del lenguaje podrían han declarado que si utilizó readonly en una propiedad automática entonces significaría "la propiedad es ajustable, pero sólo en el constructor".

Pero las características no son gratis. (Eric Gunnerson lo expresa como "Cada característica comienza con minus 100 points.") Implementar propiedades automáticas de solo lectura hubiera requerido un esfuerzo de compilación adicional para admitir el modificador de solo lectura en una propiedad (actualmente se aplica solo a los campos), para generar el respaldo apropiado campo y para transformar sets de la propiedad en asignaciones al campo de respaldo. Eso es bastante trabajo para soportar algo que el usuario podría hacer razonablemente fácil al declarar un campo de respaldo de solo lectura y escribir un getter de propiedad de una línea, y ese trabajo tendría un costo en términos de no implementar otras características.

Así que, en serio, la respuesta es que ni los diseñadores de idiomas ni los implementadores o nunca pensaron en la idea o, más probablemente, pensaron que sería bueno tenerla, pero decidieron que había mejores lugares para gastar sus recursos finitos. No existe una restricción técnica que impida que los diseñadores e implementadores de idiomas proporcionen la característica que usted sugiere: las razones se refieren más a la economía del desarrollo de software.

+1

Es Eric Gunnerson quien dice que: http://blogs.msdn.com/ericgu/archive/2004/01/12/57985.aspx. De lo contrario, gran publicación y la respuesta correcta. – jason

+1

Gracias por la corrección y el enlace, Jason - actualizado. – itowlson

+6

Fue el último. Esto ha estado en la lista desde C# 3. Nos encantaría hacerlo, pero nunca ha sido una prioridad lo suficientemente alta. Se nos ocurren literalmente cientos de ideas para las nuevas características del lenguaje y solo podemos hacer un par de ellas en cada versión. –

15

Si desea hacer que una propiedad sea de "solo lectura" en lo que respecta a la funcionalidad, hágalo solo suministrando el método get, como indicó en su publicación.

public int Width { get { return _width; } } 
public int Height { get { return _height; } } 

El compilador incluso hará referencia a estos como "de solo lectura" si intenta escribir en ellos.

Tener un término adicional de readonly para una propiedad podría entrar en conflicto con también proporcionar el método set. Parece ser una sintaxis pobre para mí, es decir, ¿cómo sabe la persona que lo lee (o el compilador) lo que tiene prioridad: readonly o set?

Además, como se explica en la respuesta a la que se hace referencia, readonly se aplica solo a los campos y limita la escritura en esos campos a la creación de instancias de la clase. Con las propiedades, no puedes escribirles (no creo) incluso dentro del constructor si solo tienen un método get.

+2

Tiene razón en que esto proporciona la misma funcionalidad. Es por eso que fue incluido como un ejemplo. Mi pregunta es: ¿por qué no puedes usar la taquigrafía de propiedad implementada automáticamente para hacer lo mismo? También sería menos desordenado, ya que no tendría que acceder directamente a los campos en su constructor; todo acceso sería a través de la propiedad. –

+1

@Matthew seguro, tal vez el equipo responsable del compilador de C# * podría haber ido por esa ruta, pero ¿no sería más confuso? Como @Nate explicó, puede tener una propiedad que sea 'readonly', simplemente no una automática, lo cual tiene sentido. Si bien puede ser * posible * lograr lo que estás hablando, me imagino que sería confuso (yo, por mi parte, estaría confundido). –

2

Propiedades puede ser de solo lectura, simplemente no propiedades automáticas.

Ambos get y set son necesarios para las propiedades automáticas, y no tiene sentido que una propiedad de solo lectura tenga un set.

Se puede definir una propiedad regular como una propiedad de sólo lectura con sólo definir el get - Sin embargo, incluso si el requisito de que tanto get y set de propiedades automáticas no existía - la propiedad de sólo lectura no podría ser se define automáticamente porque debe conocer el campo de respaldo para poder establecer su valor internamente (es decir, a través del constructor).

Supongo que podría haber una plantilla/macro o algo definido en VS para generar el código, pero no podría ser una parte del lenguaje en sí.

+0

Sería perfectamente lógico que un compilador permita la sintaxis del inicializador de campo con una propiedad de solo lectura, al menos para los campos que no implementan 'IDisposable'. – supercat

9

Usted puede hacer que una propiedad de sólo lectura automática especificando el modificador de acceso privado para el grupo como tal

public bool Property {get; private set;} 

El colocador todavía está definido pero ya no es visible fuera de la clase en la que se define la propiedad. Por otro lado, a veces es útil definir el setter como interno para que las propiedades puedan establecerse fácilmente desde el mismo ensamblado, pero no por los llamadores externos.

+9

Esto no tiene la misma semántica que 'readonly'. – jason

+0

Esto es cierto, sin embargo, una propiedad sin setter o un setter privado todavía producirá un error de tiempo de compilación y evitará la modificación del valor, así que a menos que haya algo que me falta solo y la ausencia de un setter sea funcionalmente equivalente – Crippledsmurf

+2

No impedirá la modificación del valor dentro de la clase desde fuera del constructor. – ICR

1

Creo que fundamentalmente el problema es que las propiedades son simplemente azúcar sintáctica para un campo con métodos getter/setter opcionales. Las propiedades automáticas generan el campo de respaldo, por lo que requieren el "setter" o no habría forma de establecer el valor del campo de respaldo. Dado que las propiedades realmente se asignan a los métodos, no a los campos, no tiene sentido hacerlos solo.

Incluso si está permitido, solo solo se puede aplicar a las propiedades automáticas. Para las propiedades tradicionales, puede poner código arbitrario tanto en el getter como en el setter. Incluso si el setter fuera capaz de ser invocado solo en el constructor de la clase, el getter aún podría mutar el valor basado en cualquier lógica que usted decidiera poner en él. Esto sería completamente inconsistente con el concepto de con solo, por lo que se necesitan diferentes reglas de sintaxis y soporte para propiedades automáticas/tradicionales. Dado que hay un mecanismo -utilizando propiedades tradicionales con un getter definido Y un campo de respaldo de solo lectura como en la pregunta referenciada- no veo sentido en vaciar la sintaxis de la propiedad y posiblemente introducir confusión para algo con una implementación bastante sencilla y directa usando los constructos de lenguaje actuales.

+0

muy buen punto - "Como las propiedades realmente se asignan a los métodos, no a los campos, no tiene sentido hacerlos de solo lectura". –

+2

@tvanfosson, @Ben McCormack: Eso es absolutamente falso. ¿Qué pasa con 'public int Width {get; solo set de lectura; } 'mapeo a' readonly int _width; public int Ancho {get {return _width; }} 'y' Width = 17' son legales solo en el constructor? – jason

+0

@Jason tal vez me esté perdiendo algo, pero no entiendo lo que estás diciendo. No creo que él (o yo) esté diciendo que no deberías configurar propiedades que carecen de un método 'set '(lo que las hace" de solo lectura "cuando se compilan). Él está diciendo que la ** palabra clave ** 'readonly' solo se puede aplicar a los campos, no a los métodos (y por lo tanto a las propiedades por extensión). –

0

Si el propert tiene un conjunto privado, entonces es de sólo lectura del mundo exterior, es decir:

string _name; 
public string Name 
{ 
    get{ return _name; } 
    private set { _name = value; } 
} 

O, puede ser hecha sólo lectura si es imposible tener la incubadora en absoluto, es decir:

string _name; 
public string Name 
{ 
    get{ return _name; } 
} 
Cuestiones relacionadas