[C#] Comment attribuer une valeur par défaut à une propriété Auto C #?


Answers

Modifier 1/2/15

Avec C # 6 vous pouvez initialiser directement les auto-propriétés (enfin!), Il y a maintenant d'autres réponses dans le thread qui décrivent cela.

Pour C # 5 et ci-dessous:

Bien que l'utilisation prévue de l'attribut ne soit pas de définir réellement les valeurs des propriétés, vous pouvez utiliser la réflexion pour toujours les définir de toute façon ...

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

Comment attribuer une valeur par défaut à une propriété Auto C #? J'utilise le constructeur ou je reviens à l'ancienne syntaxe.

Utilisation du constructeur:

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

Utilisation de la syntaxe de propriété normale (avec une valeur par défaut)

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

Y a-t-il un meilleur moyen?







Je pense que cela le ferait pour vous donner SomeFlag un défaut de faux.

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

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

        SomeFlag = value;        
    }
}



Ma solution consiste à utiliser un attribut personnalisé qui fournit une initialisation de propriété de valeur par défaut par une constante ou en utilisant un initialiseur de type de propriété.

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

Pour utiliser cet attribut, il est nécessaire d'hériter d'une classe à partir d'un initialiseur de classe de base spécial ou d'utiliser une méthode d'aide statique:

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

Exemple d'utilisation:

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

Sortie:

Item1
(X=3,Y=4)
StringValue



En version de C # (6.0) et plus , vous pouvez faire:

Pour les propriétés Readonly

public int ReadOnlyProp => 2;

Pour les propriétés à la fois lisibles et lisibles

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

Dans la version actuelle de C # (7.0) , vous pouvez faire: (L'extrait montre plutôt comment vous pouvez utiliser des accesseurs get / set d'expression de corps à rendre plus compact lorsque vous utilisez des champs de backing)

private string label = "Default Value";

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



Tapez Prop et appuyez sur le bouton "TAB" et Visual Studio vous suggérons le code suivant,

public int MyProperty { get; set; }

après que vous pouvez changer le modificateur, le type de données, le nom et facilement assigner l'ensemble et obtenir des valeurs.

si vous avez besoin d'utiliser une variable dans une autre classe, vous pouvez l'utiliser comme suit

public static int MyProperty { get; set; }

dans le code, vous pouvez attribuer une variable

MyProperty=1;

dans une autre classe, vous pouvez l' utiliser ,

MessageBox.Show(Classname.MyProperty);



Personnellement, je ne vois pas l'intérêt d'en faire une propriété si vous ne faites rien du tout au-delà de l'auto-propriété. Laissez-le comme un champ. Les avantages de l'encapsulation pour ces objets ne sont que des harengs rouges, car il n'y a rien derrière eux à encapsuler. Si vous avez besoin de modifier l'implémentation sous-jacente, vous pouvez toujours les refactoriser en tant que propriétés sans casser le code dépendant.

Hmm ... peut-être que ce sera le sujet de sa propre question plus tard







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



En plus de la réponse déjà acceptée, pour le scénario où vous voulez définir une propriété par défaut en fonction d'autres propriétés, vous pouvez utiliser la notation de corps d'expression sur C # 6.0 (et plus) pour des constructions encore plus élégantes et concises comme:

public class Person{

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

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

Vous pouvez utiliser ce qui précède de la manière suivante

    var p = new Person();

    p.FullName; // First Last

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

    p.FullName; // Jon Snow

Pour pouvoir utiliser la notation "=>" ci-dessus, la propriété doit être en lecture seule et vous n'utilisez pas le mot clé get accessor.

Détails sur 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; }
}



Links