Frage

Wie gibt man einer C#-Auto-Eigenschaft einen Standardwert?Ich verwende entweder den Konstruktor oder kehre zur alten Syntax zurück.

Verwendung des Konstruktors:

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

Verwendung der normalen Eigenschaftensyntax (mit einem Standardwert)

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

Gibt es einen besseren Weg?

War es hilfreich?

Lösung

Um in C# 5 und früheren Versionen automatisch implementierten Eigenschaften einen Standardwert zuzuweisen, müssen Sie dies in einem Konstruktor tun.

Die Möglichkeit, über automatische Eigenschaftsinitialisierer zu verfügen, ist seit C# 6.0 enthalten.Die Syntax lautet:

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

Andere Tipps

Bearbeitet am 02.01.15

C# 6 :

Mit C# 6 kann man Auto-Eigenschaften direkt initialisieren (endlich!), es gibt jetzt andere Antworten im Thread, die das beschreiben.

C# 5 und niedriger:

Obwohl die beabsichtigte Verwendung des Attributs nicht darin besteht, die Werte der Eigenschaften tatsächlich festzulegen, können Sie Reflektion verwenden, um sie trotzdem immer festzulegen ...

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

Wenn Sie einen Anfangswert für eine Variable einbinden, erfolgt dies ohnehin implizit im Konstruktor.

Ich würde behaupten, dass diese Syntax in C# bis 5 die beste Vorgehensweise war:

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

Dadurch haben Sie eine klare Kontrolle über die zugeordneten Auftragswerte.

Ab C#6 gibt es einen neuen Weg:

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

DefaultValueAttribute funktioniert NUR im vs-Designer.Die Eigenschaft wird nicht mit diesem Wert initialisiert.

Sehen Das DefaultValue-Attribut funktioniert nicht mit meiner Auto-Eigenschaft

Manchmal verwende ich Folgendes, wenn ich nicht möchte, dass es tatsächlich festgelegt und in meiner Datenbank beibehalten wird:

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

        set { _name = value; } 
    }
}

Wenn es sich nicht um eine Zeichenfolge handelt, kann ich das Objekt natürlich auf Null setzen ( double?, int?) und prüfen Sie, ob es null ist, einen Standardwert zurückgibt oder den Wert zurückgibt, auf den es festgelegt ist.

Dann kann ich in meinem Repository eine Überprüfung durchführen, um zu sehen, ob es mein Standardwert ist und nicht bestehen bleibt, oder einen Backdoor-Check-in durchführen, um vor dem Speichern den wahren Status des Sicherungswerts zu sehen.

Hoffentlich hilft das!

In C# 6.0 ist das ein Kinderspiel!

Sie können es in der tun Class Deklaration selbst, in den Eigenschaftendeklarationsanweisungen.

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

Beginnend mit C# 6.0, Wir können automatisch implementierten Eigenschaften einen Standardwert zuweisen.

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

Wir können auch schreibgeschützte, automatisch implementierte Eigenschaften erstellen wie:

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

Sehen: C# 6:Erste Reaktionen, Initialisierer für automatisch implementierte Eigenschaften – Von Jon Skeet

In Version von C# (6.0) und höher, du kannst tun :

Für schreibgeschützte Eigenschaften

public int ReadOnlyProp => 2;

Für beschreibbare und lesbare Eigenschaften

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

In der aktuellen Version von C# (7.0), du kannst tun :(Das Snippet zeigt vielmehr, wie Sie Get/Set-Accessoren mit Ausdruckskörpern verwenden können, um es kompakter zu machen, wenn Sie es mit Hintergrundfeldern verwenden.)

private string label = "Default Value";

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

Zusätzlich zu der bereits akzeptierten Antwort für das Szenario, in dem Sie eine Standardeigenschaft als definieren möchten Funktion von anderen Eigenschaften, die Sie nutzen können Notation des Ausdruckskörpers auf C#6.0 (und höher) für noch elegantere und prägnantere Konstrukte wie:

public class Person{

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

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

Sie können das Obige auf folgende Weise verwenden

    var p = new Person();

    p.FullName; // First Last

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

    p.FullName; // Jon Snow

Um die obige „=>“-Notation verwenden zu können, muss die Eigenschaft schreibgeschützt sein und Sie dürfen nicht das Zugriffsschlüsselwort „get“ verwenden.

Details zu MSDN

kleines vollständiges Beispiel:

using System.ComponentModel;

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

Meine Lösung besteht darin, ein benutzerdefiniertes Attribut zu verwenden, das eine Standardwert-Eigenschaftsinitialisierung durch eine Konstante oder einen Eigenschaftstyp-Initialisierer ermöglicht.

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

Um dieses Attribut zu verwenden, ist es notwendig, eine Klasse von einem speziellen Basisklasseninitialisierer zu erben oder eine statische Hilfsmethode zu verwenden:

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

Anwendungsbeispiel:

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

Ausgabe:

Item1
(X=3,Y=4)
StringValue

In C# 6 und höher können Sie einfach die Syntax verwenden:

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

Beachten Sie, dass Sie eine haben müssen readonly -Eigenschaft einfach die Menge weglassen, also:

public object Foo { get; } = bar;

Sie können auch zuweisen readonly Auto-Eigenschaften vom Konstruktor.

Zuvor habe ich wie folgt geantwortet.

Ich würde es vermeiden, dem Konstruktor einen Standardwert hinzuzufügen.Lassen Sie dies für dynamische Zuweisungen und vermeiden Sie zwei Punkte, an denen die Variable zugewiesen wird (d. h.im Typ default und im Konstruktor).Normalerweise schreibe ich in solchen Fällen einfach eine normale Eigenschaft.

Eine andere Möglichkeit besteht darin, das zu tun, was ASP.Net tut, und Standardwerte über ein Attribut zu definieren:

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

Im Konstruktor.Der Zweck des Konstruktors besteht darin, seine Datenelemente zu initialisieren.

Haben Sie versucht, das zu verwenden? DefaultValueAttribute oder ShouldSerialize- und Reset-Methoden in Verbindung mit dem Konstruktor?Ich bin der Meinung, dass eine dieser beiden Methoden erforderlich ist, wenn Sie eine Klasse erstellen, die möglicherweise auf der Designeroberfläche oder in einem Eigenschaftenraster angezeigt wird.

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

Persönlich sehe ich keinen Sinn darin, es überhaupt zu einer Eigenschaft zu machen, wenn man über die Auto-Eigenschaft hinaus überhaupt nichts tut.Belassen Sie es einfach als Feld.Der Einkapselungsvorteil für diese Artikel ist nur ein Ablenkungsmanöver, da sich dahinter nichts befindet, was eingekapselt werden könnte.Wenn Sie jemals die zugrunde liegende Implementierung ändern müssen, können Sie diese immer noch als Eigenschaften umgestalten, ohne dass abhängiger Code beschädigt wird.

Hmm...Vielleicht wird dies später Gegenstand einer eigenen Frage sein

Zur Verdeutlichung: Ja, Sie müssen im Konstruktor Standardwerte für von Klassen abgeleitete Objekte festlegen.Sie müssen sicherstellen, dass der Konstruktor mit dem richtigen Zugriffsmodifikator für die Konstruktion vorhanden ist, wo er verwendet wird.Wenn das Objekt nicht instanziiert ist, z.B.es hat keinen Konstruktor (z.B.statische Methoden), dann kann der Standardwert durch das Feld festgelegt werden.Der Grund dafür ist, dass das Objekt selbst nur einmal erstellt wird und Sie es nicht instanziieren.

@Darren Kopp – gute Antwort, sauber und korrekt.Und um es noch einmal zu wiederholen: Sie KÖNNEN Konstruktoren für abstrakte Methoden schreiben.Sie müssen beim Schreiben des Konstruktors lediglich über die Basisklasse darauf zugreifen:

Konstruktor in der Basisklasse:

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

Konstruktor bei Abgeleitet / Konkret / Unterklasse:

public SubClass() : base() { }

Der Punkt hier ist, dass die aus der Basisklasse gezogene Instanzvariable möglicherweise Ihren Basisfeldnamen verbirgt.Festlegen des aktuellen instanziierten Objektwerts mit "This". Ermöglicht es Ihnen, Ihr Objekt in Bezug auf die aktuelle Instanz und die erforderlichen Berechtigungsstufen (Zugriffsmodifikatoren) korrekt zu bilden, in denen Sie es instanziieren.

Verwenden Sie den Konstruktor, denn „Wenn der Konstruktor fertig ist, sollte die Konstruktion abgeschlossen sein“.Eigenschaften sind wie Zustände, die Ihre Klassen enthalten. Wenn Sie einen Standardzustand initialisieren müssten, würden Sie dies in Ihrem Konstruktor tun.

Sie können es einfach so ausdrücken

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

Ich denke, das würde es für Sie tun, wenn Sie SomeFlag den Standardwert „false“ geben würden.

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

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

        SomeFlag = value;        
    }
}

Inline initialisieren: Die Verwendung von Konstruktoren zum Initialisieren ist eine schlechte Praxis und führt später zu weiteren bahnbrechenden Änderungen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top