2323 Stimmen

Was ist der beste Weg, um eine C# Auto-Eigenschaft einen Anfangswert zu geben?

Wie gibt man einer C#-Auto-Eigenschaft einen Anfangswert?

Entweder verwende ich den Konstruktor, oder ich greife auf die alte Syntax zurück.

Verwendung des Konstruktors:

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

Verwendung der normalen Eigenschaftssyntax (mit einem Anfangswert)

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

Gibt es einen besseren Weg?

2946voto

Darren Kopp Punkte 74401

In C# 5 und früher mussten Sie einen Konstruktor verwenden, um automatisch implementierten Eigenschaften einen Anfangswert zu geben.

Seit C# 6.0 können Sie den Anfangswert in-line angeben. Die Syntax lautet:

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

DefaultValueAttribute soll vom VS-Designer (oder einem anderen Verbraucher) verwendet werden, um einen Standardwert anzugeben, nicht einen Anfangswert. (Auch wenn im entworfenen Objekt der Anfangswert der Standardwert ist).

Zur Kompilierzeit DefaultValueAttribute hat keinen Einfluss auf die generierte AWL und es wird nicht gelesen, um die Eigenschaft auf diesen Wert zu initialisieren (siehe Das DefaultValue-Attribut funktioniert nicht mit meiner Auto-Eigenschaft ).

Beispiele für Attribute, die sich auf die IL auswirken, sind ThreadStaticAttribute , CallerMemberNameAttribute , ...

14 Stimmen

Es ist erwähnenswert, dass dies auch für Getter-only-Eigenschaften funktioniert: public int X { get; } = x;

330voto

Chuck Rostance Punkte 6622

Bearbeitet am 1/2/15

C# 6 :

Mit C# 6 können Sie Auto-Properties direkt initialisieren (endlich!), es gibt jetzt andere Antworten, die das beschreiben.

C# 5 und niedriger :

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

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

6 Stimmen

Stimmabgabe -1: Im besten Fall sieht es subjektiv ein wenig ordentlicher aus als die Initialisierung im Konstruktor. Der Preis dafür ist die Verwirrung von Entwicklern, die neu in die Codebasis einsteigen, eine schlechtere Leistung, eine semantische Änderung der Bedeutung eines eingebauten Attributs, die Zulassung von Konstanten, schwer zu erkennende Standardwerte bei mehreren Attributen, die Notwendigkeit, sich daran zu erinnern, dies bei jeder Konstruktorüberladung auszuführen, und die Möglichkeit, Standardwerte sowohl im Attribut als auch im Konstruktor zu definieren.

215voto

Keith Punkte 141163

Wenn Sie einen Anfangswert für eine Variable einfügen, wird dies ohnehin implizit im Konstruktor geschehen.

Ich würde argumentieren, dass diese Syntax war beste Praxis in C # bis 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; }
}

So haben Sie eine klare Kontrolle über die Reihenfolge, in der die Werte zugewiesen werden.

Ab C#6 gibt es einen neuen Weg:

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

75voto

crucible Punkte 3011

Manchmal verwende ich dies, wenn ich nicht möchte, dass die Daten tatsächlich in meiner Datenbank gespeichert und persistiert werden:

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 Zeichenkette handelt, könnte ich das Objekt nullable (double?, int?) machen und prüfen, ob es null ist, einen Standardwert zurückgeben oder den Wert zurückgeben, auf den es gesetzt ist.

Dann kann ich in meinem Repository prüfen, ob es sich um meinen Standardwert handelt und nicht bestehen bleibt, oder ich kann durch eine Hintertür den wahren Status des Sicherungswertes prüfen, bevor ich speichere.

Ich hoffe, das hilft!

39 Stimmen

return _name ?? "Default Name"; ist wahrscheinlich sogar deutlicher, dass Ihr

23 Stimmen

@abatishchev: Das ist allerdings nicht dasselbe. Der Code von Crucibles würde "Default Name" zurückgeben, wenn die Zeichenkette "" oder null ist, aber mit Ihrem Ansatz würde "Default Name" nur zurückgegeben, wenn sie null ist. Außerdem ist es diskutabel, ob "??" oder "IsNullOrEmpty" eindeutiger ist.

2 Stimmen

Der Punkt ist ein Standardwert, so dass eine Prüfung auf Null den Punkt verfehlt. Die Antwort von Keith zeigt das, indem er ihn im Ctor initialisiert. Wenn es um den dB geht, sehe ich nicht wirklich einen großen Unterschied zu einem Standard-Spaltenwert und einer Nicht-Null-Spalte, die unabhängig von der Anzahl der Klassenfelder effizienter sein wird. Ich werde nicht abstimmen, aber ich fordere die Entwickler auf, darüber nachzudenken, anstatt Null-/Leer-Prüfungen in Ihren Eigenschaftsprozeduren durchzuführen.

72voto

Shiva Punkte 19502

In C# 6.0 ist das ein Kinderspiel!

Sie können dies in der Class Deklaration selbst, in den Erklärungen zu den Eigenschaften.

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

3 Stimmen

Ich habe nicht C#6.0 noch, und wurde überprüfen, um zu sehen, welche Version ich für Standardwerte auf Auto-Eigenschaften benötigt. Beseitigt C# 6.0 auch die Notwendigkeit zu haben { get; set; } ou { get; private set; } da sonst das Setzen des Wertes vom Compiler blockiert würde?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X