Domanda

Come si assegna un valore predefinito a una proprietà automatica C#?O utilizzo il costruttore o ripristino la vecchia sintassi.

Utilizzando il costruttore:

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

Utilizzando la normale sintassi delle proprietà (con un valore predefinito)

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

C'è un modo migliore?

È stato utile?

Soluzione

In C# 5 e versioni precedenti, per assegnare un valore predefinito alle proprietà implementate automaticamente, è necessario farlo in un costruttore.

La possibilità di avere inizializzatori di proprietà automatici è inclusa a partire da C# 6.0.La sintassi è:

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

Altri suggerimenti

Modificato il 2/1/15

Do#6 :

Con C# 6 puoi inizializzare direttamente le proprietà automatiche (finalmente!), ora ci sono altre risposte nel thread che lo descrivono.

Do# 5 e precedenti:

Sebbene l'uso previsto dell'attributo non sia quello di impostare effettivamente i valori delle proprietà, puoi utilizzare la riflessione per impostarli sempre comunque...

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

Quando si incorpora un valore iniziale per una variabile, verrà comunque eseguito implicitamente nel costruttore.

Direi che questa sintassi era la migliore pratica in C# fino a 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; }
}

Poiché ciò ti dà un chiaro controllo sui valori dell'ordine, vengono assegnati.

A partire da C#6 c'è un nuovo modo:

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

DefaultValueAttribute funziona SOLO nel vs designer.Non inizializzerà la proprietà su quel valore.

Vedere L'attributo DefaultValue non funziona con la mia proprietà Auto

A volte lo uso, se non voglio che sia effettivamente impostato e persistente nel mio db:

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

        set { _name = value; } 
    }
}

Ovviamente se non è una stringa allora potrei rendere l'oggetto nullable ( double?, int?) e controlla se è null, restituisce un valore predefinito o restituisce il valore su cui è impostato.

Quindi posso effettuare un controllo nel mio repository per vedere se è il mio valore predefinito e non persiste, oppure effettuare un controllo backdoor per vedere il vero stato del valore di supporto, prima di salvare.

Spero che aiuti!

In C# 6.0 questo è un gioco da ragazzi!

Puoi farlo nel Class dichiarazione stessa, nelle dichiarazioni di dichiarazione di proprietà.

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

A partire da C# 6.0, Possiamo assegnare un valore predefinito alle proprietà implementate automaticamente.

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

Possiamo anche creare proprietà implementate automaticamente di sola lettura come:

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

Vedere: Do#6:Prime reazioni, Inizializzatori per proprietà implementate automaticamente - Di Jon Skeet

Nella versione di C# (6.0) e versioni successive, tu puoi fare :

Per le proprietà di sola lettura

public int ReadOnlyProp => 2;

Sia per le proprietà scrivibili che leggibili

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

Nella versione attuale di C# (7.0), tu puoi fare :(Lo snippet mostra piuttosto come utilizzare le funzioni di accesso get/set con corpo dell'espressione per renderlo più compatto quando si utilizza con campi sottostanti)

private string label = "Default Value";

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

Oltre alla risposta già accettata, per lo scenario in cui si desidera definire una proprietà predefinita come a funzione di altre proprietà che puoi utilizzare notazione del corpo dell'espressione su C#6.0 (e versioni successive) per costrutti ancora più eleganti e concisi come:

public class Person{

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

    public string First { get; set; } = "First";
    public string Last { get; set; } = "Last";
}

È possibile utilizzare quanto sopra nel modo seguente

    var p = new Person();

    p.FullName; // First Last

    p.First = "Jon";
    p.Last = "Snow";

    p.FullName; // Jon Snow

Per poter utilizzare la notazione "=>" di cui sopra, la proprietà deve essere di sola lettura e non si utilizza la parola chiave get accessor.

Dettagli su MSDN

piccolo campione completo:

using System.ComponentModel;

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

La mia soluzione consiste nell'utilizzare un attributo personalizzato che fornisca l'inizializzazione della proprietà del valore predefinito tramite costante o utilizzando l'inizializzatore del tipo di proprietà.

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

Per utilizzare questo attributo è necessario ereditare una classe da uno speciale inizializzatore di classe base o utilizzare un metodo helper statico:

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

Esempio di utilizzo:

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

Produzione:

Item1
(X=3,Y=4)
StringValue

In C# 6 e versioni successive puoi semplicemente utilizzare la sintassi:

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

Tieni presente che per avere a readonly proprietà omette semplicemente il set, in questo modo:

public object Foo { get; } = bar;

Puoi anche assegnare readonly proprietà automatiche dal costruttore.

Prima di ciò ho risposto come di seguito.

Eviterei di aggiungere un valore predefinito al costruttore;lascialo per le assegnazioni dinamiche ed evita di avere due punti in cui la variabile viene assegnata (ad es.il tipo default e nel costruttore).In genere in questi casi scrivo semplicemente una proprietà normale.

Un'altra opzione è fare ciò che fa ASP.Net e definire le impostazioni predefinite tramite un attributo:

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

Nel costruttore.Lo scopo del costruttore è inizializzare i suoi membri dati.

Hai provato a utilizzare il file Attributo ValoreDefault O Metodi ShouldSerialize e Reset insieme al costruttore?Ritengo che uno di questi due metodi sia necessario se stai creando una classe che potrebbe essere visualizzata nell'area di progettazione o in una griglia delle proprietà.

public Class ClassName{
    public int PropName{get;set;}
    public ClassName{
        PropName=0;  //Default Value
    }
}
private string name;
public string Name 
{
    get 
    {
        if(name == null)
        {
            name = "Default Name";
        }
        return name;
    }
    set
    {
        name = value;
    }
}

Personalmente, non vedo il motivo di renderlo una proprietà se non hai intenzione di fare altro oltre all'auto-proprietà.Lascialo come un campo.Il vantaggio dell'incapsulamento per questi elementi è solo una falsa pista, perché dietro di essi non c'è nulla da incapsulare.Se mai avessi bisogno di modificare l'implementazione sottostante, sei comunque libero di rifattorizzarli come proprietà senza interrompere il codice dipendente.

Hmm...forse questo sarà oggetto di una domanda più tardi

Per chiarire, sì, è necessario impostare i valori predefiniti nel costruttore per gli oggetti derivati ​​dalla classe.Dovrai assicurarti che il costruttore esista con il modificatore di accesso corretto per la costruzione, dove utilizzato.Se l'oggetto non è istanziato, ad es.non ha costruttore (ad es.metodi statici), il valore predefinito può essere impostato dal campo.Il ragionamento qui è che l'oggetto stesso verrà creato solo una volta e non ne verrà creata un'istanza.

@Darren Kopp: buona risposta, pulita e corretta.E per ribadire, PUOI scrivere costruttori per metodi astratti.Devi solo accedervi dalla classe base quando scrivi il costruttore:

Costruttore nella classe base:

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

Costruttore presso Derivato / Calcestruzzo / Sottoclasse:

public SubClass() : base() { }

Il punto qui è che la variabile di istanza estratta dalla classe base potrebbe seppellire il nome del campo base.Impostazione del valore dell'oggetto istanziato corrente usando "questo". Ti consentirà di formare correttamente il tuo oggetto rispetto all'istanza corrente e ai livelli di autorizzazione richiesti (modificatori di accesso) in cui lo si sta istanticando.

Utilizzare il costruttore perché "Quando il costruttore è terminato, la costruzione dovrebbe essere terminata".le proprietà sono come gli stati conservati dalle tue classi, se dovessi inizializzare uno stato predefinito, lo faresti nel tuo costruttore.

Puoi dirlo semplicemente così

    public sealed  class Employee
{
    public int Id { get; set; } = 101;
}
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; }
}

Penso che questo farebbe al caso tuo, dando a SomeFlag un valore predefinito falso.

private bool _SomeFlagSet = false;
public bool SomeFlag
{
    get
    {
        if (!_SomeFlagSet)
            SomeFlag = false;        

        return SomeFlag;
    }
    set
    {
        if (!_SomeFlagSet)
            _SomeFlagSet = true;

        SomeFlag = value;        
    }
}

inizializzare in linea, utilizzare i costruttori per inizializzare è una cattiva pratica e porterà a ulteriori modifiche importanti in seguito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top