una - tipo de valor c#
¿Cómo le das a una propiedad automática de C#un valor predeterminado? (22)
En C # 6.0 esto es una brisa!
Puede hacerlo en la declaración de Class
sí misma, en las declaraciones de declaración 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;
}
}
¿Cómo le das a una propiedad automática de C # un valor predeterminado? Utilizo el constructor o vuelvo a la sintaxis anterior.
Usando el Constructor:
class Person
{
public Person()
{
Name = "Default Name";
}
public string Name { get; set; }
}
Usando sintaxis de propiedad normal (con un valor predeterminado)
private string name = "Default Name";
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
¿Hay alguna manera mejor?
¿Ha intentado usar los http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx o ShouldSerialize y Reset junto con el constructor? Siento que uno de estos dos métodos es necesario si está creando una clase que podría aparecer en la superficie del diseñador o en una cuadrícula de propiedades.
A veces utilizo esto, si no quiero que realmente esté configurado y persistido 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 es una cadena, podría hacer que el objeto sea anulable (¿doble? ¿Int?) Y verificar si es nulo, devolver un valor predeterminado o devolver el valor establecido.
Luego puedo hacer una verificación en mi repositorio para ver si es mi valor 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!
Además de la respuesta ya aceptada, para el escenario cuando desea definir una propiedad predeterminada en función de otras propiedades, puede usar la notación del cuerpo de la 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";
}
Puedes 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 usar la palabra clave obtener acceso.
Detalles en MSDN
Creo que esto lo haría por ti, dándole 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;
}
}
Cuando inserta un valor inicial para una variable, se hará implícitamente en el constructor de todos modos.
Yo diría que esta sintaxis 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 SOLAMENTE funciona en el diseñador vs. No inicializará la propiedad a ese valor.
Ver el atributo DefaultValue no funciona con mi propiedad automática
Editar 1/2/15
Con C # 6 puede inicializar propiedades automáticas directamente (¡por fin!), Ahora hay otras respuestas en el hilo que describen eso.
Para C # 5 y abajo:
Aunque el uso previsto del atributo no es realmente establecer los valores de las propiedades, puede usar la reflexión 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; }
}
En C # 5 y versiones anteriores, para asignar un valor predeterminado a las propiedades implementadas automáticamente, debe hacerlo en un constructor.
La capacidad de tener inicializadores de propiedades automáticos se incluye desde C # 6.0. La sintaxis es:
public int X { get; set; } = x; // C# 6 or higher
En C # 6 y más arriba puedes simplemente usar la sintaxis:
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 propiedades automáticas de readonly
desde el constructor.
Antes de esto respondí como abajo.
Evitaría agregar un valor predeterminado al constructor; deje eso para asignaciones dinámicas y evite tener dos puntos en los que se asigna la variable (es decir, el tipo predeterminado y en el constructor). Por lo general, simplemente escribiría 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.
En la versión de C # (6.0) y superior , puedes hacer:
Para propiedades de solo lectura
public int ReadOnlyProp => 2;
Para propiedades tanto de escritura como de lectura
public string PropTest { get; set; } = "test";
En la versión actual de C # (7.0) , puede hacer: (El fragmento de código muestra más bien cómo puede usar los accesos get / set con 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;
}
Inicializar en línea, usar constructores para inicializar es una mala práctica y llevará a más cambios de ruptura más adelante.
Mi solución es usar un atributo personalizado que proporcione la inicialización de propiedades de 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 auxiliar 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<string> 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
Para aclarar, sí, debe establecer valores predeterminados en el constructor para objetos derivados de clase. Deberá asegurarse de que el constructor exista con el modificador de acceso adecuado para la construcción donde se usa. Si el objeto no está instanciado, por ejemplo, no tiene un constructor (por ejemplo, métodos estáticos), el campo puede establecer el valor predeterminado. El razonamiento aquí es que el objeto en sí se creará solo una vez y no se crea una instancia.
@Darren Kopp - buena respuesta, limpio y correcto. Y para reiterar, PUEDES 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 Derivado / Concreto / Subclase:
public SubClass() : base() { }
El punto aquí es que la variable de instancia extraída de la clase base puede enterrar su nombre de campo base. Configuración del valor de objeto instanciado actual utilizando "esto". le permitirá formar correctamente su objeto con respecto a la instancia actual y los niveles de permiso requeridos (modificadores de acceso) donde lo está creando.
Personalmente, no veo el punto de convertirlo en una propiedad si no vas a hacer nada más allá de la propiedad automática. Solo déjalo como un campo. El beneficio de encapsulación para estos elementos son solo pistas falsas, porque no hay nada detrás de ellos para encapsular. Si alguna vez necesita cambiar la implementación subyacente, todavía puede refactorizarlos como propiedades sin romper ningún código dependiente.
Hmm ... tal vez este sea el tema de su propia pregunta más tarde
Use el constructor porque "Cuando el constructor haya terminado, la construcción debería estar terminada". las propiedades son como los estados que tienen sus clases; si tuviera que inicializar un estado predeterminado, lo haría en su constructor.
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; }
}
A partir de 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";
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; }
}
private string name;
public string Name
{
get
{
if(name == null)
{
name = "Default Name";
}
return name;
}
set
{
name = value;
}
}
public Class ClassName{
public int PropName{get;set;}
public ClassName{
PropName=0; //Default Value
}
}