¿Cuál es la mejor manera de dar un valor inicial a una propiedad automática de C #?

¿Cómo se le da a una propiedad automática de C # un valor inicial?

Utilizo el constructor o vuelvo a la sintaxis anterior.

Usando el constructor:

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

Usando la sintaxis de propiedad normal (con un valor inicial)

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

¿Hay una mejor manera?

preguntado el 02 de septiembre de 08 a las 19:09

22 Respuestas

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

Desde C # 6.0, puede especificar el valor inicial en línea. La sintaxis es:

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

DefaultValueAttribute está destinado a ser utilizado por el diseñador de VS (o cualquier otro consumidor) para especificar un valor predeterminado, no un valor inicial. (Incluso si está en un objeto diseñado, el valor inicial es el valor predeterminado).

En tiempo de compilación DefaultValueAttribute no afectará el IL generado y no se leerá para inicializar la propiedad a ese valor (ver El atributo DefaultValue no funciona con mi propiedad automática).

Ejemplo de atributos que impactan la IL son ThreadStaticAttribute, CallerMemberNameAttribute...

Respondido 11 Oct 19, 16:10

Editado el 1/2/15

C # 6 :

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

C # 5 y menos:

Aunque el uso previsto del atributo no es establecer realmente 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; }
}

Respondido el 31 de enero de 19 a las 06:01

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 la orden se asignan.

A partir de C # 6 hay una nueva forma:

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

respondido 06 nov., 19:09

A veces uso esto, si no quiero que se establezca y persista en mi base de datos:

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, entonces podría hacer que el objeto sea anulable (¿doble ?, ¿int?) Y verificar si es nulo, devolver un valor predeterminado o devolver el valor en el que está configurado.

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!

Respondido el 03 de Septiembre de 08 a las 00:09

return _name ?? "Default Name"; probablemente incluso sea más claro que tu ... abatishchev

@abatishchev: aunque eso no es lo mismo. El código de crisoles devolvería "Nombre predeterminado" si la cadena es "" o nula, pero si usa su enfoque, devolverá "Nombre predeterminado" solo en caso de que sea nulo. Además, se puede discutir si "??" o "IsNullOrEmpty" es más claro. - Sebastián Mach

El punto es un valor predeterminado, por lo que una comprobación anulable anula el punto. La respuesta de Keith demuestra que al inicializarlo en Ctor. Si es por los dB, realmente no veo mucha diferencia que tener un valor de columna predeterminado y convertirla en una columna no nula que será más eficiente independientemente del número de campos de clase. No votaré en contra, pero insto a los desarrolladores a pensar en esto en lugar de tener cheques nulos / vacíos en los procedimientos de su propiedad. - Jeremy Thompson

Para aclarar cada vez que llame a una propiedad de clase, hará una verificación nula / vacía, mientras que los dB solo lo harán en INSERT o UPDATE, que generalmente son el 20% del trabajo de dB. En cambio, potencialmente cada propiedad de cadena tiene una llamada adicional, es una pérdida de ciclos de CPU y una mala elección de diseño en mi humilde opinión. Además, ahora hay tipos de referencia nulos, por lo que es más común lidiar con los que aceptan valores NULL. - Jeremy Thompson

¡En C # 6.0 esto es muy sencillo!

Puedes hacerlo en el Class declaración en sí, 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;
    }
}

Respondido el 29 de Septiembre de 17 a las 17:09

Todavía no tengo C # 6.0 y estaba comprobando qué versión necesitaba para los valores predeterminados en las propiedades automáticas. ¿C # 6.0 también elimina la necesidad de tener { get; set; } or { get; private set; } ya que, de lo contrario, el compilador bloquearía la configuración del valor? - Freefaller

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

Respondido 24 Jul 15, 18:07

En versión de C # (6.0) y superior, tu puedes hacer :

Para propiedades de solo lectura

public int ReadOnlyProp => 2;

Para propiedades de escritura y lectura

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

En la versión actual de C # (7.0), puede hacer: (El fragmento muestra cómo puede usar los descriptores de acceso 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; 
 }

Respondido el 26 de Septiembre de 17 a las 06:09

Está bien, pero solo el segundo de los tres ejemplos es una propiedad automática. - Aluan Haddad

Además, considere el ejemplo class C { public DateTime P { get; } = DateTime.Now; public DateTime Q => DateTime.Now; } donde ambas propiedades P e Q tener solo un captador, pero los comportamientos de P e Q ¡son muy diferentes! - Jeppe Stig Nielsen

Además de la respuesta ya aceptada, para el escenario en el que desee definir una propiedad predeterminada como función de otras propiedades que puede utilizar notación del cuerpo 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 utilizar 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 utilizar la palabra clave de acceso get.

Detalles sobre MSDN

Respondido 30 Oct 16, 02:10

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

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

Tenga en cuenta que para tener un readonly propiedad simplemente omite el conjunto, así:

public object Foo { get; } = bar;

También puede asignar readonly auto-propiedades del constructor.

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

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). Normalmente, simplemente escribiría una propiedad normal en tales casos.

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

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

Respondido el 17 de junio de 17 a las 16:06

Esto está mal; no hay problema de "doble asignación" con el constructor .... - marca corchetes

Vaya, esto es una maravilla del pasado. Creo recordar que esto se basó en la lectura de la especificación (extracto parcial aquí: msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx ). Dado el tiempo y la cantidad de versiones (y Roslyn), este podría dejar de ser el caso. Aunque se agradecería una contrarreferencia. - Lex

La asignación predeterminada ocurre automáticamente ya sea que use o no un valor inicial o asigne en el constructor. Hay una ligera diferencia semántica: las asignaciones de campos ocurren antes de las llamadas al constructor, pero la asignación nula seguirá ocurriendo. Ver 10.4.5 "todos los campos de instancia ... primero se inicializan a sus valores predeterminados, y luego se ejecutan los inicializadores de campo de instancia" msdn.microsoft.com/en-us/library/aa645757(VS.71).aspx - marca corchetes

Mi solución es usar un atributo personalizado que proporcione inicialización de propiedad de valor predeterminado por constante o usando un 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 de un 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

Respondido el 18 de enero de 13 a las 07:01

Como se indicó anteriormente, usar la reflexión para inicializar los valores predeterminados es lento y excesivo. Inicialice en el constructor, use una propiedad que no sea automática o en c # 6 y superior, use la notación simplificada que se muestra en la respuesta aceptada: KinSlayerUY

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; }
}

respondido 21 nov., 16:11

Eso no funcionará. DefaultValueAttribute es solo una sugerencia de serialización, no se establecerá ShowGroup a true porque el valor predeterminado para cualquier booleano es false. - boris b

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

Respondido 18 Jul 16, 17:07

Puedes ponerlo así de manera simple

public sealed  class Employee
{
    public int Id { get; set; } = 101;
}

Respondido 20 ago 19, 04:08

private string name;
public string Name 
{
    get 
    {
        if(name == null)
        {
            name = "Default Name";
        }
        return name;
    }
    set
    {
        name = value;
    }
}

respondido 01 nov., 18:14

Creo que el autor de la pregunta quería una propiedad automática, es decir, una propiedad no abstracta en una clase o estructura donde se usa solo get; con un punto y coma (a menudo combinado con set;) para indicar que el compilador debe generar el cuerpo del get descriptor de acceso automáticamente. - Jeppe Stig Nielsen

Además, este código tiene el efecto secundario de volver al valor predeterminado cuando se establece explícitamente en nulo. - Marcos

¿Has intentado usar el AtributoValorPredeterminado or Métodos 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.

Respondido el 02 de Septiembre de 08 a las 22:09

Para aclarar, sí, debe establecer valores predeterminados en el constructor para los objetos derivados de la clase. Deberá asegurarse de que el constructor exista con el modificador de acceso adecuado para la construcción donde se use. Si el objeto no está instanciado, por ejemplo, no tiene 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 lo instanciará.

@Darren Kopp: buena respuesta, limpia y correcta. 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 Derivado / Concreto / Subclase:

public SubClass() : base() { }

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

Respondido el 07 de junio de 13 a las 15:06

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

Respondido el 04 de Septiembre de 14 a las 21:09

Utilice el constructor porque "Cuando el constructor esté terminado, la construcción debería estar terminada". las propiedades son como los estados que mantienen sus clases, si tuviera que inicializar un estado predeterminado, lo haría en su constructor.

Respondido el 11 de enero de 16 a las 11:01

Personalmente, no veo el sentido de convertirlo en una propiedad en absoluto si no va a hacer nada más allá de la propiedad automática. Déjalo como un campo. El beneficio de encapsulación de 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, aún puede refactorizarlas como propiedades sin romper ningún código dependiente.

Hmm ... tal vez este sea el tema de su propia pregunta más adelante.

Respondido el 03 de Septiembre de 08 a las 04:09

@Joel: el enlace de datos y otras herramientas basadas en la reflexión suelen esperar propiedades en lugar de campos. - Chris granjero

No puede refactorizar un campo en una propiedad automática sin romper el código de llamada. Puede que tenga el mismo aspecto, pero el código generado es diferente. Con las propiedades automáticas, el código de llamada llama a get_propname y set_propname detrás de las cubiertas, mientras que solo accede al campo directamente si es un campo. - david reyes

Sí, esto es muy antiguo, desde entonces he revisado mi posición: stackoverflow.com/questions/205568/… - Joel Coehoorn

Tampoco puede acceder a un campo a través de los límites de AppDomain, solo una propiedad o un método. - jacob krall

Si su posición ha cambiado, tal vez debería editar / eliminar esta respuesta. - zev perro de Pomerania

Sé que esta es una pregunta antigua, pero surgió cuando estaba buscando cómo tener un valor predeterminado que se hereda con la opción de anular, se me ocurrió

//base class
public class Car
{
    public virtual string FuelUnits
    {
        get { return "gasoline in gallons"; }
        protected set { }
    }
}
//derived
public class Tesla : Car
{
    public override string FuelUnits => "ampere hour";
}

contestado el 25 de mayo de 20 a las 01:05

Precaución: esto no establece un valor inicial, crea un descriptor de acceso get que devuelve una cadena constante. Si el valor de FuelUnits se establece en otra cadena, FuelUnits ignorará ese valor y continuará devolviendo la cadena literal definida en el get. - AjimOthy

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; }
}

Respondido 31 Jul 14, 14:07

¡Bienvenido a Stack Overflow! Para que lo sepas, abordar una vieja pregunta como esta generalmente está mal visto a menos que tengas buena información nueva. Sin embargo, en este caso, varios otros ya han publicado sobre el atributo DefaultValue. Si alguien más ya publicó lo que ibas a decir, es más apropiado votarlo haciendo clic en la flecha hacia arriba sobre el número al lado de su respuesta. - fuego eagle

@fire: comentar requiere 50 reputación. Votar también requiere reputación, IIRC. - ben voigt

-1 ya que esto no inicializa la propiedad al valor predeterminado. - Gyum zorro

solo funciona en el diseñador como se indica en todas las respuestas anteriores: KinSlayerUY

Creo que esto lo haría por ya darle 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;        
    }
}

Respondido el 06 de diciembre de 13 a las 21:12

Esta no es una propiedad automática. - Aluan Haddad

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.