2011-02-09 21 views
81

Estoy tomando una clase C# en este momento y estoy tratando de encontrar la mejor manera de hacer las cosas. Vengo de un entorno Java y, por lo tanto, solo estoy familiarizado con las mejores prácticas de Java; ¡Soy un novato de C#!Buenas prácticas de getters, setters y properties. Java vs. C#

En Java si tengo una propiedad privada, hago esto;

private String name; 

public void setName(String name) { 
    this.name = name; 
} 

public String getName() { 
    return this.name; 
} 

En C#, veo que hay muchas formas de hacerlo.

puedo hacerlo como Java:

private string name; 

public void setName(string name) { 
    this.name = name; 
} 

public string getName() { 
    return this.name; 
} 

O puedo hacerlo de esta manera:

private string name; 

public string Name { 
    get { return name; } 
    set { name = value; } 
} 

O:

public string Name { get; set; } 

¿Cuál debo usar, y lo son las advertencias o sutilezas involucradas con cada enfoque? Al crear clases, sigo las mejores prácticas generales que conozco de Java (especialmente la lectura de Java efectivo). Entonces, por ejemplo, estoy a favor de la inmutabilidad (que proporciona setters solo cuando es necesario). Tengo curiosidad por ver cómo estas prácticas se ajustan a las diversas formas de proporcionar setters y getters en C#; esencialmente, ¿cómo traduciría las mejores prácticas del mundo de Java a C#?

EDITAR

estaba fijando esto como un comentario a la respuesta de Jon Skeet, pero luego se puso de largo:

¿Qué hay de una propiedad no trivial (es decir, con un procesamiento significativo y validación tal vez)? ¿Podría seguir exponiéndolo a través de una propiedad pública pero con la lógica encapsulada en get y set? ¿Por qué debería/debería hacer esto sobre tener métodos dedicados setter y getter (con lógica de procesamiento y validación asociada).

Respuesta

79

Pre-C# 6

que haría uso de la última de ellas, una propiedad trivial. Tenga en cuenta que llamaría a esto una propiedad pública, ya que tanto los getters como los setters son públicos.

La inmutabilidad es un poco molesta con las propiedades implementadas automáticamente; no se puede escribir una propiedad automática que solo tenga un getter; lo más cerca que puede llegar es:

public string Foo { get; private set; } 

que no es realmente inmutable ... sólo inmutable fuera de su clase.Así que es posible que desee utilizar una verdadera sólo lectura propiedad en lugar:

private readonly string foo; 
public string Foo { get { return foo; } } 

que definitivamente no quieren escribir getName() y setName(). En algunos casos tiene sentido escribir métodos Get/Set en lugar de utilizar propiedades, especialmente si pueden ser caros y desea enfatizar eso. Sin embargo, querría seguir la convención de nomenclatura .NET de PascalCase para conocer los métodos, y no querría que una propiedad trivial como esta se implementara con los métodos normales de todos modos, una propiedad es mucho más idiomática aquí.

C# 6

propiedades de sólo lectura implementadas de forma automática Hurra, por fin hemos adecuado:

// This can only be assigned to within the constructor 
public string Foo { get; } 

Lo mismo sucede con las propiedades de sólo lectura, que hacen necesidad de hacer algún trabajo, que pueda utilizar las propiedades del cuerpo del miembro:

public double Area => height * width; 
+5

Más exactamente: cualquier reiew código señalará la forma en java es un truco que está pasando por alto langauge válido y tiempo de ejecución (!) construye y mata el uso de la propiedad como proeprty (es decir, object.property = "value"). En algunos equipos, esto daría lugar a una agradable charla sobre la actitud, dependiendo de la antigüedad combinada con un incentivo para poner esa actitud al uso de un competidor. En serio, NO LUCHES LA LANGAUGE. Especialmente como el "camino" de Java es un truco que se eligió para no modificar el lenguaje para el soporte de bienes inmuebles. – TomTom

+1

Supongo que la buena noticia es que mi respuesta no parece contradecir nada de lo que ha mencionado. La mala noticia es que tus dedos son mucho más rápidos que los míos. Gran idea y gracias por los detalles adicionales. – jeremyalan

+4

Para responder a la edición: puede usar los métodos get/set con la cantidad de lógica que desee. A menudo hacemos esto, especialmente para la validación.La mejor práctica, sin embargo, no es tener mucha lógica lenta (acceso a la base de datos, por ejemplo), lógica peligrosa (lanzamiento de excepción) o mutación (cambiando mucho estado) en las propiedades. Se espera que una propiedad actúe más o menos como un estado simple. Cualquier cosa más debería indicarse usando una función en su lugar. – CodexArcanum

4

Independientemente de la forma que elija en C#, el resultado final es el mismo. Obtendrá una variable de respaldo con métodos getter y setter separados. Al usar las propiedades, está siguiendo las mejores prácticas, por lo que es una cuestión de qué tan detallado desea obtener.

Personalmente elegiría auto-propiedades, la última versión: public string Name { get; set; }, ya que ocupan la menor cantidad de espacio. Y siempre puede expandir estos en el futuro si necesita agregar algo como validación.

11

Usar propiedades en C#, no obtener/configurar métodos. Están ahí para su conveniencia y es idiomático.

En cuanto a sus dos ejemplos de C#, uno es simplemente azúcar sintáctico para el otro. Use la propiedad auto si todo lo que necesita es un simple contenedor alrededor de una variable de instancia, use la versión completa cuando necesite agregar lógica en el getter y/o setter.

3

Siempre que sea posible prefiero string Name { get; set; } público, ya que es escueto y fácil de leer. Sin embargo, puede haber momentos en que este es necesario

private string name; 

public string Name { 
    get { return name; } 
    set { name = value; } 
} 
+2

¿Puedes explicar cuándo y por qué es necesario ese tipo de cosas? – Jesper

+0

En este momento no puedo pensar en una razón para usar la segunda versión. Solo dije 'quizás haya momentos en que sea necesario'. Odio usar absolutos a menos que sea positivo. – SquidScareMe

+3

¿Y por qué es esto 'lolz'? Puede mostrar su apoyo para un comentario por votaciones ascendentes. – SquidScareMe

4

En C# propiedades a favor para exponer campos privados para obtener y/o establecer. La forma que mencionas es una propiedad automática donde get y set generan automáticamente un campo de respaldo de pivote oculto para ti.

Favorezco las propiedades automáticas cuando sea posible, pero nunca debe hacer un par de método set/get en C#.

4
public string Name { get; set; } 

Esto es simplemente una auto-implemented property, y es técnicamente lo mismo que una propiedad normal. Se creará un campo de respaldo al compilar.

Todas las propiedades se convierten eventualmente en funciones, por lo que la implementación compilada real al final es la misma que se usa en Java.

Utilice propiedades implementadas automáticamente cuando no tenga que realizar operaciones específicas en el campo de respaldo. Utilice una propiedad ordinaria de lo contrario. Use las funciones get y set cuando la operación tenga efectos secundarios o sea computacionalmente costosa, use propiedades de lo contrario.

3

Como se mencionó, todos estos enfoques dan como resultado el mismo resultado. Lo más importante es elegir una convención y aferrarse a ella. Prefiero usar los dos últimos ejemplos de propiedades.

3

En C# la forma preferida es a través de las propiedades en lugar de los métodos getX() y setX(). Además, tenga en cuenta que C# no requiere que las propiedades tengan tanto un get como un set; puede tener propiedades de solo obtener y propiedades de solo ajuste.

public boolean MyProperty 
{ 
    get { return something; } 
} 

public boolean MyProperty 
{ 
    set { this.something = value; } 
} 
3

En primer lugar voy a tratar de explicar lo que escribió:

// private member -- not a property 
private string name; 

/// public method -- not a property 
public void setName(string name) { 
    this.name = name; 
} 

/// public method -- not a property 
public string getName() { 
    return this.name; 
} 

// yes it is property structure before .Net 3.0 
private string name; 
public string Name { 
    get { return name; } 
    set { name = value; } 
} 

Esta estructura también se utiliza hoy en día, pero es más adecuado si quiere hacer alguna funcionalidad adicional, por ejemplo, cuando un valor es set puede analizarlo para capitalizarlo y guardarlo en miembro privado para uso interno alterno.

Con .NET Framework 3,0

// this style is introduced, which is more common, and suppose to be best 
public string Name { get; set; } 

//You can more customize it 
public string Name 
{ 
    get; 
    private set; // means value could be set internally, and accessed through out 
} 

le deseo mejor suerte en C#

16

Si todo lo que necesita es una variable para almacenar algunos datos:

public string Name { get; set; } 

¿Quieres hacer que parezca ¿solo lectura?

public string Name { get; private set; } 

O mejor aún ...

private readonly string _name; 

... 

public string Name { get { return _name; } } 

quiere hacer algo de valor de comprobación antes de asignar la propiedad?

public string Name 
{ 
    get { return m_name; } 
    set 
    { 
     if (value == null) 
     throw new ArgumentNullException("value"); 

     m_name = value; 
    } 
} 

En general, el GetXyz() y SetXyz() sólo se utilizan en ciertos casos, y sólo hay que utilizar en su intestino cuando se siente bien. En general, diría que espero que la mayoría de las propiedades get/set no contengan mucha lógica y tengan muy pocos efectos secundarios inesperados. Si leer un valor de propiedad requiere invocar un servicio u obtener información de un usuario para construir el objeto que estoy solicitando, entonces lo envolvería en un método y lo llamaría algo así como BuildXyz(), en lugar de GetXyz().

+1

No me lanzar excepciones en propiedades, prefiero usar fijadores método con contratos para especificar este tipo de comportamiento específico. Si una propiedad es de tipo int, esperaría que cada int califique. Algo que llama a arrojar excepciones no es simple, en mi opinión, las invocaciones de tipo INotifyPropertyChanged están más en esa línea según yo. – flindeberg

+3

privado setter! = Inmutable – piedar

+0

piedar tiene razón. Un setter privado solo significa que no puedo hacer asignaciones, pero aún puedo usar 'myList.Add()', por ejemplo (siempre que el objeto esté expuesto a cambios, es mutable). –

2

como la mayoría de las respuestas aquí, use las propiedades automáticas. Intuitivo, menos líneas de código y es más limpio. Si debe serializar su clase, marque la clase [Serializable]/con el atributo [DataConract]. Y si está utilizando [DataContract] marca el miembro con

[DataMember(Name="aMoreFriendlyName")] 
public string Name { get; set; } 

setter privado o público depende de su preferencia.

También tenga en cuenta que las propiedades automáticas requieren tanto getters como setters (públicos o privados).

/*this is invalid*/ 
public string Name 
{ 
    get; 
    /* setter omitted to prove the point*/ 
} 

Alternativamente, si sólo desea obtener/set, crear un campo de respaldo a sí mismo