¿Cómo le das a C # Auto-Property un valor predeterminado?

¿Cómo le das a C # Auto-Property un valor predeterminado? Yo uso el constructor o vuelvo a la syntax anterior.

Usando el Constructor:

class Person { public Person() { Name = "Default Name"; } public string Name { get; set; } } 

Usar la syntax de propiedad normal (con un valor predeterminado)

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

¿Hay una mejor manera?

En C # 5 y anteriores, para dar a las propiedades implementadas automáticamente un valor predeterminado, debe hacerlo en un constructor.

La capacidad de tener inicializadores de propiedad de auto se incluye desde C # 6.0. La syntax es:

 public int X { get; set; } = x; // C# 6 or higher 

Editar 1/2/15

Con C # 6 puede inicializar auto-propiedades directamente (¡finalmente!), Ahora hay otras respuestas en el hilo que describen eso.

Para C # 5 y abajo:

Aunque el uso previsto del atributo no es establecer realmente los valores de las propiedades, puede usar el reflection para establecerlos siempre de todos modos …

 public class DefaultValuesTest { public DefaultValuesTest() { foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this)) { DefaultValueAttribute myAttribute = (DefaultValueAttribute)property.Attributes[typeof(DefaultValueAttribute)]; if (myAttribute != null) { property.SetValue(this, myAttribute.Value); } } } public void DoTest() { var db = DefaultValueBool; var ds = DefaultValueString; var di = DefaultValueInt; } [System.ComponentModel.DefaultValue(true)] public bool DefaultValueBool { get; set; } [System.ComponentModel.DefaultValue("Good")] public string DefaultValueString { get; set; } [System.ComponentModel.DefaultValue(27)] public int DefaultValueInt { get; set; } } 

Cuando en línea un valor inicial para una variable, se hará de forma implícita en el constructor de todos modos.

Yo diría que esta syntax fue la mejor práctica en C # hasta 5:

 class Person { public Person() { //do anything before variable assignment //assign initial values Name = "Default Name"; //do anything after variable assignment } public string Name { get; set; } } 

Como esto le da un control claro de los valores de orden, se asignan.

A partir de C # 6 hay una nueva forma:

 public string Name { get; set; } = "Default Name" 

DefaultValueAttribute SÓLO funciona en el diseñador vs. No inicializará la propiedad a ese valor.

Ver el atributo DefaultValue no funciona con mi propiedad de auto

A veces uso esto, si no quiero que realmente se establezca y persista en mi db:

 class Person { private string _name; public string Name { get { return string.IsNullOrEmpty(_name) ? "Default Name" : _name; } set { _name = value; } } } 

Obviamente, si no se trata de una cadena, entonces podría hacer que el objeto sea nulo (double ?, int?) Y comprobar si es nulo, devolver un valor predeterminado o devolver el valor establecido.

Luego puedo verificar en mi repository para ver si es mi predeterminado y no persistir, o hacer una verificación de puerta trasera para ver el verdadero estado del valor de respaldo, antes de guardar.

¡Espero que ayude!

Comenzando con C # 6.0 , podemos asignar un valor predeterminado a las propiedades implementadas automáticamente.

 public string Name { get; set; } = "Some Name"; 

También podemos crear propiedades implementadas automáticamente de solo lectura como:

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

Ver: C # 6: Primeras reacciones, Inicializadores para propiedades implementadas automáticamente – Por Jon Skeet

En C # 6.0 esto es muy sencillo.

Puede hacerlo en la propia statement de Class , en las declaraciones de statement de propiedad.

 public class Coordinate { public int X { get; set; } = 34; // get or set auto-property with initializer public int Y { get; } = 89; // read-only auto-property with initializer public int Z { get; } // read-only auto-property with no initializer // so it has to be initialized from constructor public Coordinate() // .ctor() { Z = 42; } } 

pequeña muestra completa:

 using System.ComponentModel; private bool bShowGroup ; [Description("Show the group table"), Category("Sea"),DefaultValue(true)] public bool ShowGroup { get { return bShowGroup; } set { bShowGroup = value; } } 

En la versión de C # (6.0) y superior , puede hacer:

Para las propiedades de Readonly

 public int ReadOnlyProp => 2; 

Para propiedades escriturables y legibles

 public string PropTest { get; set; } = "test"; 

En la versión actual de C # (7.0) , puede hacer lo siguiente: (El fragmento muestra más bien cómo puede usar los accesadores get / set con cuerpo de expresión para hacer que sea más compacto cuando se usa con campos de respaldo)

 private string label = "Default Value"; // Expression-bodied get / set accessors. public string Label { get => label; set => this.label = value; } 

Mi solución es usar un atributo personalizado que proporcione la inicialización de la propiedad del valor predeterminado por constante o utilizando el inicializador de tipo de propiedad.

 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class InstanceAttribute : Attribute { public bool IsConstructorCall { get; private set; } public object[] Values { get; private set; } public InstanceAttribute() : this(true) { } public InstanceAttribute(object value) : this(false, value) { } public InstanceAttribute(bool isConstructorCall, params object[] values) { IsConstructorCall = isConstructorCall; Values = values ?? new object[0]; } } 

Para usar este atributo es necesario heredar una clase del inicializador de clase base especial o usar un método de ayuda estático:

 public abstract class DefaultValueInitializer { protected DefaultValueInitializer() { InitializeDefaultValues(this); } public static void InitializeDefaultValues(object obj) { var props = from prop in obj.GetType().GetProperties() let attrs = prop.GetCustomAttributes(typeof(InstanceAttribute), false) where attrs.Any() select new { Property = prop, Attr = ((InstanceAttribute)attrs.First()) }; foreach (var pair in props) { object value = !pair.Attr.IsConstructorCall && pair.Attr.Values.Length > 0 ? pair.Attr.Values[0] : Activator.CreateInstance(pair.Property.PropertyType, pair.Attr.Values); pair.Property.SetValue(obj, value, null); } } } 

Ejemplo de uso:

 public class Simple : DefaultValueInitializer { [Instance("StringValue")] public string StringValue { get; set; } [Instance] public List Items { get; set; } [Instance(true, 3,4)] public Point Point { get; set; } } public static void Main(string[] args) { var obj = new Simple { Items = {"Item1"} }; Console.WriteLine(obj.Items[0]); Console.WriteLine(obj.Point); Console.WriteLine(obj.StringValue); } 

Salida:

 Item1 (X=3,Y=4) StringValue 

Además de la respuesta ya aceptada, para el escenario en el que desea definir una propiedad predeterminada como una función de otras propiedades, puede usar la notación corporal de expresión en C # 6.0 (y superior) para construcciones aún más elegantes y concisas, como:

 public class Person{ public string FullName => $"{First} {Last}"; // expression body notation public string First { get; set; } = "First"; public string Last { get; set; } = "Last"; } 

Puede usar lo anterior de la siguiente manera

  var p = new Person(); p.FullName; // First Last p.First = "Jon"; p.Last = "Snow"; p.FullName; // Jon Snow 

Para poder utilizar la notación “=>” anterior, la propiedad debe ser de solo lectura y no debe utilizarse la palabra clave get accessor.

Detalles en MSDN

En C # 6 y superior, puede simplemente usar la syntax:

 public object Foo { get; set; } = bar; 

Tenga en cuenta que para tener una propiedad de solo readonly simplemente omita el conjunto, así:

 public object Foo { get; } = bar; 

También puede asignar auto-propiedades de readonly desde el constructor.

Antes de esto, respondí como a continuación.

Evitaría agregar un valor predeterminado al constructor; deje eso para las asignaciones dinámicas y evite tener dos puntos en los que se asigna la variable (es decir, el tipo predeterminado y en el constructor). Normalmente, simplemente escribo una propiedad normal en tales casos.

Otra opción es hacer lo que hace ASP.Net y definir los valores predeterminados a través de un atributo:

http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx

En el constructor El propósito del constructor es inicializar sus miembros de datos.

¿Has intentado utilizar los métodos DefaultValueAttribute o ShouldSerialize and Reset junto con el constructor? Siento que uno de estos dos métodos es necesario si está haciendo una clase que podría aparecer en la superficie del diseñador o en una cuadrícula de propiedades.

 public Class ClassName{ public int PropName{get;set;} public ClassName{ PropName=0; //Default Value } } 

Personalmente, no veo el sentido de convertirlo en una propiedad en absoluto si no va a hacer nada más allá de la propiedad de automóviles. Solo déjalo como un campo. El beneficio de encapsulación para estos ítems son solo arenques rojos, porque no hay nada detrás de ellos que encapsular. Si alguna vez necesita cambiar la implementación subyacente, aún puede refactorizarlos como propiedades sin romper ningún código dependiente.

Hmm … tal vez este será el tema de su propia pregunta más tarde

Para aclarar, sí, debe establecer valores predeterminados en el constructor para objetos derivados de clase. Deberá asegurarse de que el constructor existe con el modificador de acceso adecuado para la construcción donde se usa. Si el objeto no se crea una instancia, por ejemplo, no tiene constructor (por ejemplo, métodos estáticos), entonces el valor predeterminado se puede establecer por el campo. El razonamiento aquí es que el objeto mismo se creará solo una vez y no se lo creará.

@Darren Kopp: buena respuesta, limpio y correcto. Y para reiterar, PUEDE escribir constructores para métodos abstractos. Solo necesita acceder a ellos desde la clase base al escribir el constructor:

Constructor en la clase base:

 public BaseClassAbstract() { this.PropertyName = "Default Name"; } 

Constructor en derivadas / hormigón / subclase:

 public SubClass() : base() { } 

El punto aquí es que la variable de instancia extraída de la clase base puede enterrar el nombre de tu campo base. Configurando el valor actual del objeto instanciado usando “this”. le permitirá formar correctamente su objeto con respecto a la instancia actual y los niveles de permisos requeridos (modificadores de acceso) donde está instanciando.

Use el constructor porque “Cuando el constructor finaliza, la construcción debe estar terminada”. las propiedades son como estados que tienen sus clases, si tuviera que inicializar un estado predeterminado, lo haría en su constructor.

 class Person { /// Gets/sets a value indicating whether auto /// save of review layer is enabled or not [System.ComponentModel.DefaultValue(true)] public bool AutoSaveReviewLayer { get; set; } } 

Creo que esto lo haría por dar a SomeFlag un valor predeterminado de falso.

 private bool _SomeFlagSet = false; public bool SomeFlag { get { if (!_SomeFlagSet) SomeFlag = false; return SomeFlag; } set { if (!_SomeFlagSet) _SomeFlagSet = true; SomeFlag = value; } } 

Inicializar en línea, usar constructores para inicializar es una mala práctica y dará lugar a más cambios de última hora.

    Intereting Posts