[c#] Come si fornisce a C # Auto-Property un valore predefinito?



Answers

Modifica 1/2/15

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

Per C # 5 e seguenti:

Sebbene l'uso previsto dell'attributo non sia quello di impostare effettivamente i valori delle proprietà, è possibile utilizzare la riflessione per impostarli sempre in ogni caso ...

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

Come si fornisce a C # Auto-Property un valore predefinito? Uso il costruttore o ripristino la vecchia sintassi.

Usando il Costruttore:

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

Uso della sintassi di proprietà normale (con un valore predefinito)

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

C'è un modo migliore?




In Version of C # (6.0) e versioni successive, puoi fare:

Per proprietà di sola lettura

public int ReadOnlyProp => 2;

Per entrambe le proprietà scrivibili e leggibili

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

Nella versione corrente di C # (7.0) , puoi fare: (Lo snippet mostra piuttosto come usare gli accessi get / set con corpo dell'espressione per renderlo più compatto quando si usa con i campi di supporto)

private string label = "Default Value";

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



Personalmente, non vedo assolutamente il senso di renderlo una proprietà se non hai intenzione di fare qualcosa oltre la proprietà automatica. Lasciatelo come un campo. Il vantaggio di incapsulamento per questi oggetti è solo una falsa pista, perché non c'è niente dietro a loro da incapsulare. Se hai sempre bisogno di modificare l'implementazione sottostante, sei comunque libero di rifattenerli come proprietà senza violare alcun codice dipendente.

Hmm ... forse questo sarà l'oggetto della sua stessa domanda in seguito




Penso che lo farebbe per ya givng SomeFlag un valore predefinito di false.

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

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

        SomeFlag = value;        
    }
}



La mia soluzione è di usare un attributo personalizzato che fornisce l'inizializzazione della proprietà del valore di default 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 un inizializzatore speciale della classe base o utilizzare un metodo di supporto 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



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



Oltre alla risposta già accettata, per lo scenario in cui si desidera definire una proprietà predefinita come funzione di altre proprietà è possibile utilizzare la notazione del corpo dell'espressione su C # 6.0 (e 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";
}

Puoi usare 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 "=>" sopra, la proprietà deve essere di sola lettura e non si utilizza la parola chiave get accessor.

Dettagli su MSDN




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



Digitare Prop e premere il pulsante "TAB" e Visual Studio suggerire il seguente codice,

public int MyProperty { get; set; }

dopo puoi modificare il modificatore, il tipo di dati, il nome e assegnare facilmente set e ottenere valori.

se hai bisogno di usare qualche variabile in un'altra classe puoi usarla come follwing,

public static int MyProperty { get; set; }

nel codice è possibile assegnare una variabile

MyProperty=1;

in un'altra classe puoi usare questo,

MessageBox.Show(Classname.MyProperty);









Related