2012-03-02 19 views
13

Mi manager me ha preguntado si es una buena práctica usar una propiedad con un setter, pero no getter.¿Hay alguna razón para tener una propiedad sin getter?

public class PropertyWrapper 
{ 
    private MyClass _field; 

    public MyClass Property 
    { 
     set { _field = value; } 
    } 

    public string FirstProperty 
    { 
     get { return _field.FirstProperty; } 
    } 

    public string SecondProperty 
    { 
     get { return _field.SecondProperty; } 
    } 
} 

Él estaría utilizando otras propiedades para exponer propiedades de un campo privado, establecido por este colocador.

Mi sugerencia era utilizar un campo privado y configurarlo en el constructor, que funciona bien en este escenario. Si tuviera que tener primero un objeto construido (quizás incluso usando polimorfismo), preferiría un método Load, en lugar de una propiedad sin getter.

Pero estoy interesado. Los dos estamos muy preocupados por las mejores prácticas y tratamos de asegurarnos de que nuestro código esté estandarizado. ¿Alguien tiene artículos oficiales sobre propiedades sin getter? O mejor aún, ¿un ejemplo de este uso en el propio .NET Framework?

+2

No tiene nada de intrínsecamente incorrecto, pero no es común. ¿Por qué tener una propiedad para esto si solo puedes configurarlo? – Oded

+3

Ver http://stackoverflow.com/questions/4695551/write-only-properties-whats-the-point – kaj

+0

@KAJ ¡gracias! No encontré ese en mi búsqueda al principio. – Connell

Respuesta

16

artículo Oficial: Design Guidelines for Developing Class Libraries -> Member Design Guidelines -> Property Design

No proporcionar propiedades de configuración solamente.

Si no se puede proporcionar el captador de propiedades, utilice un método para implementar la funcionalidad . El nombre del método debe comenzar con Set seguido de lo que habría sido el nombre de la propiedad. Por ejemplo, AppDomain tiene un método llamado SetCachePath en lugar de tener una propiedad de solo establecimiento llamada CachePath.

2

No hay nada malo en tener una propiedad sin getter, si eso es lo que hace que su código sea más comprensible y fácil de mantener. Sin embargo, los buenos casos para esto son probablemente extremadamente raros.

Lo mejor que he usado en las propiedades getter-less es para las clases de pruebas unitarias cuyas propiedades tienen instaladores inaccesibles. Por ejemplo:

public class MyClass 
{ 
    public int MyId { get; protected set; } 
} 

public class MyClass_Test : MyClass 
{ 
    public int MyId_Set 
    { 
     set { MyId = value; } 
    } 
} 

este modo puede utilizar un MyClass_Test en la prueba de la unidad y pre-establecer un valor para MyId con la capacidad de prueba de la unidad de un método particular.

Además, en respuesta directa a su ejemplo, usando un private get sería probablemente la mejor manera de evitarlo: nada

public class PropertyWrapper 
{  
    public MyClass Property { private get; set; } 

    public string FirstProperty 
    { 
     get { return Property.FirstProperty; } 
    } 

    public string SecondProperty 
    { 
     get { return Property.SecondProperty; } 
    } 
} 
+1

Agregar algunas habilidades a la clase solo para pruebas unitarias parece ser un olor a código. –

+0

Supongo que podría especificar que la clase '_Test' existe solo dentro del contexto de la prueba unitaria, me permite configurar el estado del objeto y probar métodos individuales como unidades únicas. – eouw0o83hf

+0

Estoy hablando de proteger setter de 'MyClass.MyId'. Si eso se va a usar solo para pruebas unitarias, eso en mi humilde opinión no es un buen diseño. –

0

de Ther a decir que no puede hacer esto, pero lo hace parecer un poco extraño. Tendría una propiedad privada y un método que la configurara, por ejemplo,

private string _test; 

public void SetTest(string test) 
{ 
_test = test; 
} 
0

Debe recordar por qué existen las propiedades. Sustituyen el siguiente patrón

class Foo 
{ 
    private Bar _bar; 

    public Bar GetBar() 
    { 
     return _bar; 
    } 

    public void SetBar(Bar bar) 
    { 
     _bar = bar; 
    } 
} 

Si bien tener una propiedad sin Setter parece extraño para mí, no creo que tener un método set sin método Get parece extraño en absoluto.

De hecho, estoy bastante seguro de que las propiedades son azúcar sintáctica y se reescriben como métodos get/set. O al menos realmente cerca.

+0

Soy de la misma opinión. 'SetBar' sin un' GetBar' parece normal, ¡pero esto es lo que el compilador hace a una propiedad C# de todos modos! – Connell

3

No tengo artículos oficiales o ejemplos .. única opinión.

Y en mi opinión, una propiedad que no se puede leer es una bestia que enojará y confundirá.

Todo se reduce a la intención. Una propiedad dice "Tengo la intención de permitir que el consumidor me lea, y posiblemente incluso me escriba". Una función llamada algo así como "SetSomeAttribute" declara un intento de solo escritura.

También está el todo, son mis datos, ¿por qué no puedo leerlo?

Por lo tanto, en mi opinión, nunca hay una buena razón para utilizar una propiedad de solo escritura.

+0

El único buen ejemplo que me viene a la mente es algo relacionado con las contraseñas. Tal vez hay una estructura de datos de credenciales que le permite leer/escribir el nombre de usuario, pero la contraseña es de solo configuración. Podría tener métodos internos para compararlo con otra instancia (es decir, la almacenada con los valores correctos) para determinar internamente si es válida, o podría tener una opción para acceder públicamente a un hash. – Servy

+0

@Servy: no estoy seguro de seguir. Si una propiedad es de solo escritura, entonces NOBODY, ni siquiera otra instancia de esa clase/estructura puede leer la propiedad. Entonces, ¿cómo se llevaría a cabo esta comparación? En este caso, optaría por un método .SetPassword() en lugar de una propiedad de solo escritura, y comparar las propiedades públicas .Hash. –

+0

Bueno, el código en el setter obviamente necesitaría almacenarlo en algún medio de almacenamiento privado para que la clase pueda acceder internamente; y la propiedad autogenerada sin getter es obviamente inútil (e incluso puede ser eliminada por el compilador). Sería básicamente lo mismo que tener un método setPassword, estoy de acuerdo. No estoy diciendo que esto sea mejor, simplemente que este es un caso raro en el que no me opondría si vi a un miembro del equipo implementarlo. – Servy

8

Considerando que las preguntas son: ¿Alguien tiene algún artículo oficial sobre las propiedades sin getter-less? O mejor aún, ¿un ejemplo de este uso en el propio .NET Framework? y no sobre la opinión; Escribí una aplicación de prueba rápida para leer a través de todas las propiedades de todo el tipo de todos los conjuntos cargados en una aplicación de consola por defecto:

foreach (var assem in AppDomain.CurrentDomain.GetAssemblies()) 
{ 
    foreach (var type in assem.GetTypes()) 
    { 
     foreach (var prop in type.GetProperties()) 
     { 
      if (!prop.CanRead) 
       Console.WriteLine("Assembly: {0}; Type: {1}; Property: {2}", assem.FullName, type.Name, prop.Name); 
     } 
    } 
} 

Los resultados son los siguientes:

Asamblea

: mscorlib , Versión = 4.0.0.0, Cultura = neutral, PublicKeyToken = b77a5c561934e089; Tipo: FileIOAccess; Propiedad: PathDiscovery

Ensamblaje: mscorlib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; Tipo: RedirectionProxy; Propiedad: ObjectMode

Parece que el marco lo usa con moderación. Sugeriría hacer lo mismo.

EDITAR

Curiosamente, ejecutar el mismo código con el depurador adjunta produce muchos más resultados:

Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: FileIOAccess; Property: PathDiscovery 
Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: RedirectionProxy; Property: ObjectMode 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AxHost; Property: Site 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DataGridTextBoxColumn; Property: PropertyDescriptor 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: FirstDisplayedFrozenCol 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: FirstDisplayedFrozenRow 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedFrozenCol 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedFrozenRow 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedScrollingRow 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ErrorProvider; Property: Site 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: WebBrowserBase; Property: Site 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: WebBrowser; Property: Site 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DropDownButton; Property: UseComboBoxTheme 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridErrorDlg; Property: Details 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridErrorDlg; Property: Message 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DropDownHolder; Property: ResizeUp 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridViewEdit; Property: DontFocus 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridViewEdit; Property: DisableMouseHook 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: MouseHook; Property: DisableMouseHook 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ManifestSignedXml; Property: Resolver 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ContainerProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: RightToLeftProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: TopDownProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: BottomUpProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ElementProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: VerticalElementProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: IconComparer; Property: SortOrder 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: MultiPropertyDescriptorGridEntry; Property: PropertyValue 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlDocument; Property: XmlResolver 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlDocument; Property: InnerText 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ProcessThread; Property: IdealProcessor 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ProcessThread; Property: ProcessorAffinity 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlAttribute; Property: InnerText 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlAttribute; Property: InnerXml 
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AnonymousPipeServerStream; Property: ReadMode 
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AnonymousPipeClientStream; Property: ReadMode 
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ManifestSignedXml; Property: Resolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlNullResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSecureResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: Proxy 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: CachePolicy 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlReaderSettings; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlTextReader; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlValidatingReader; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: NamespaceManager 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: Navigator 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: EndNode 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlAttribute; Property: InnerText 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlAttribute; Property: InnerXml 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlDocument; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlDocument; Property: InnerText 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUnspecifiedAttribute; Property: InnerText 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUnspecifiedAttribute; Property: InnerXml 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlPreloadedResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XslTransform; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSchemaSet; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSchemaValidator; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XsdValidator; Property: Context 
+0

Brillante respuesta! Ejecuté este código y obtuve los mismos resultados. Le mostré a mi gerente también;) ¡Gracias! – Connell

+0

Estos resultados no indican si la propiedad es de acceso público o no, lo que puede ser una medida interesante. –

+0

El hecho de que MS lo haga no significa que sea una buena práctica. –

-3

Usted puede tener propiedades que son más ordenado, y sobre la cual se puede ejercer el control de acceso completa, sin la _localVariable desordenada, y la sintaxis de la propiedad.

ejemplos:

/// <summary> 
    /// Publicly readable, privately settable. 
    /// </summary> 
    public int FirstProperty { get; private set; } 

    /// <summary> 
    /// Entirely private 
    /// </summary> 
    private int SecondProperty { get; set; } 
+1

-1: respuesta no relacionada: la pregunta era "es propiedad sin ser útil" y la respuesta es "ver cómo obtener". –

0

Potencialmente, se pueden utilizar para la inyección de dependencia cuando por alguna razón ni la inyección de constructor ni método funciona para usted.

Pero no me puedo imaginar tal caso.

0

Bueno, pueden ser un buen uso de los campos privados en inicializadores de objeto:

var obj = new MyClass 
{ 
    Prop1 = value1, 
    Prop2 = value2 
}; 

que podría ser una forma alternativa de simplemente escribir como parámetros del constructor:

var obj = new MyClass(value1, value2); 

Pero si hay muchos parámetros (opcionales), propiedades writeonly pueden ser útiles.

0

Como ya se ha sugerido, creo que la respuesta es la más significativa en el contexto del problema. Puedo pensar en dos alternativas para tener una propiedad setter only, que podría valer la pena probar para ver cuál es más significativa:

  1. Defina un método independiente que acepte un solo parámetro.
  2. Define un getter que siempre devuelve el mismo valor (por ejemplo, nulo). Si esto tiene sentido o sorpresas depende del contexto.
Cuestiones relacionadas