Question

Comment attribuer une valeur par défaut à une propriété automatique C# ?Soit j'utilise le constructeur, soit 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;
    }
}

Existe-t-il une meilleure façon ?

Était-ce utile?

La solution

En C# 5 et versions antérieures, pour attribuer une valeur par défaut aux propriétés implémentées automatiquement, vous devez le faire dans un constructeur.

La possibilité d’avoir des initialiseurs de propriétés automatiques est incluse depuis C# 6.0.La syntaxe est :

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

Autres conseils

Edité le 02/01/15

C#6 :

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

C# 5 et versions antérieures:

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

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

Lorsque vous insérez une valeur initiale pour une variable, cela sera de toute façon implicite dans le constructeur.

Je dirais que cette syntaxe était la meilleure pratique en C# jusqu'à 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; }
}

Comme cela vous donne un contrôle clair sur les valeurs de commande attribuées.

Depuis C#6, il existe une nouvelle méthode :

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

DefaultValueAttribute fonctionne UNIQUEMENT dans le concepteur vs.Il n'initialisera pas la propriété à cette valeur.

Voir L'attribut DefaultValue ne fonctionne pas avec ma propriété automatique

Parfois, j'utilise ceci, si je ne veux pas qu'il soit réellement défini et conservé dans ma base de données :

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

        set { _name = value; } 
    }
}

Évidemment, si ce n'est pas une chaîne, je pourrais rendre l'objet nullable ( double ?, int ?) et vérifiez s'il est nul, renvoie une valeur par défaut ou renvoie la valeur à laquelle il est défini.

Ensuite, je peux vérifier dans mon référentiel pour voir s'il s'agit de ma valeur par défaut et ne pas persister, ou effectuer une vérification par porte dérobée pour voir le véritable statut de la valeur de sauvegarde, avant de sauvegarder.

J'espère que cela pourra aider!

En C# 6.0, c’est un jeu d’enfant !

Vous pouvez le faire dans le Class déclaration elle-même, dans les déclarations de propriété.

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

À partir de C# 6.0, Nous pouvons attribuer une valeur par défaut aux propriétés implémentées automatiquement.

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

Nous pouvons également créer une propriété implémentée automatiquement en lecture seule comme :

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

Voir: C#6 :Premières réactions, Initialiseurs pour les propriétés implémentées automatiquement - Par Jon Skeet

Dans la version de C# (6.0) et supérieur, tu peux faire :

Pour les propriétés en lecture seule

public int ReadOnlyProp => 2;

Pour les propriétés inscriptibles et lisibles

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

Dans la version actuelle de C# (7.0), tu peux faire :(L'extrait montre plutôt comment vous pouvez utiliser les accesseurs get/set de corps d'expression pour rendre plus compact lors de l'utilisation avec des champs de sauvegarde)

private string label = "Default Value";

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

En plus de la réponse déjà acceptée, pour le scénario où vous souhaitez définir une propriété par défaut comme fonction d'autres propriétés que vous pouvez utiliser notation du corps de l'expression sur C#6.0 (et supérieur) 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

Afin de 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

petit échantillon complet :

using System.ComponentModel;

private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
    get { return bShowGroup; }
    set { bShowGroup = 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 d'un initialiseur de classe de base spécial ou d'utiliser une méthode d'assistance 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);
}

Sortir:

Item1
(X=3,Y=4)
StringValue

En C# 6 et supérieur, vous pouvez simplement utiliser la syntaxe :

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

Notez que pour avoir un readonly property omettez simplement l'ensemble, de la sorte :

public object Foo { get; } = bar;

Vous pouvez également attribuer readonly propriétés automatiques du constructeur.

Avant cela, j'ai répondu comme ci-dessous.

J'éviterais d'ajouter une valeur par défaut au constructeur ;laissez cela pour les affectations dynamiques et évitez d'avoir deux points auxquels la variable est affectée (c'est-à-direle type par défaut et dans le constructeur).En règle générale, j'écrirais simplement une propriété normale dans de tels cas.

Une autre option consiste à faire ce que fait ASP.Net et à définir les valeurs par défaut via un attribut :

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

Dans le constructeur.Le but du constructeur est d'initialiser ses données membres.

Avez-vous essayé d'utiliser le DefaultValueAttribute ou Méthodes ShouldSerialize et Reset en collaboration avec le constructeur ?J'ai l'impression que l'une de ces deux méthodes est nécessaire si vous créez une classe qui pourrait apparaître sur l'aire du concepteur ou dans une grille de propriétés.

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

Personnellement, je ne vois pas du tout l'intérêt d'en faire une propriété si vous ne comptez rien faire du tout au-delà de la propriété automobile.Laissez-le simplement comme un champ.L'avantage de l'encapsulation pour ces éléments ne sont que des harengs rouges, car il n'y a rien derrière eux à encapsuler.Si jamais vous avez besoin de modifier l'implémentation sous-jacente, vous êtes toujours libre de 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

Pour clarifier, oui, vous devez définir des valeurs par défaut dans le constructeur pour les objets dérivés de classe.Vous devrez vous assurer que le constructeur existe avec le modificateur d'accès approprié pour la construction, le cas échéant.Si l'objet n'est pas instancié, par ex.il n'a pas de constructeur (par ex.méthodes statiques), la valeur par défaut peut être définie par le champ.Le raisonnement ici est que l'objet lui-même ne sera créé qu'une seule fois et que vous ne l'instancierez pas.

@Darren Kopp - bonne réponse, propre et correcte.Et pour réitérer, vous POUVEZ écrire des constructeurs pour les méthodes abstraites.Il vous suffit d'y accéder depuis la classe de base lors de l'écriture du constructeur :

Constructeur à la classe de base :

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

Constructeur chez Dérivé / Béton / Sous-Classe :

public SubClass() : base() { }

Le point ici est que la variable d'instance tirée de la classe de base peut enterrer le nom de votre champ de base.Définition de la valeur d'objet instanciée actuelle à l'aide de "This". Vous permettra de former correctement votre objet par rapport à l'instance actuelle et aux niveaux d'autorisation requis (modificateurs d'accès) où vous le stabilisez.

Utilisez le constructeur car "Lorsque le constructeur est terminé, la construction doit être terminée".les propriétés sont comme les états détenus par vos classes, si vous deviez initialiser un état par défaut, vous le feriez dans votre constructeur.

Vous pouvez simplement dire comme ça

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

Je pense que cela le ferait pour vous en donnant à SomeFlag la valeur par défaut false.

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

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

        SomeFlag = value;        
    }
}

initialiser en ligne, utiliser des constructeurs pour initialiser est une mauvaise pratique et entraînera des modifications plus importantes plus tard.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top