variable - parameter with default value c#




Wie geben Sie einer C#-Auto-Eigenschaft einen Standardwert? (15)

Wie geben Sie einer C # -Auto-Eigenschaft einen Standardwert? Ich benutze entweder den Konstruktor oder stelle die alte Syntax wieder her.

Verwenden des Konstruktors:

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

Verwenden 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?


In C # 6.0 ist das ein Kinderspiel!

Sie können dies in der Klassendeklaration selbst in den Deklarationsanweisungen tun.

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

Bearbeiten 1/2/15

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

Für C # 5 und darunter:

Obwohl die beabsichtigte Verwendung des Attributs nicht darin besteht, die Werte der Eigenschaften tatsächlich zu setzen, können Sie die Reflektion immer verwenden, um sie trotzdem 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; }
}


Ich denke, das würde es tun, damit SomeFlag den Standardwert false bekommt.

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

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

        SomeFlag = value;        
    }
}

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

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

Beachten Sie, dass eine readonly die Menge einfach readonly :

public object Foo { get; } = bar;

Sie können dem Konstruktor auch readonly zuweisen.

Davor habe ich wie folgt geantwortet.

Ich würde vermeiden, dem Konstruktor einen Standard hinzuzufügen; belassen Sie das für dynamische Zuweisungen und vermeiden Sie zwei Punkte, denen die Variable zugewiesen ist (dh der Typ default und im Konstruktor). Normalerweise würde ich in solchen Fällen einfach eine normale Eigenschaft schreiben.

Eine andere Möglichkeit ist, was ASP.Net tut und defaults über ein Attribut zu definieren:

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


In Version von C # (6.0) und höher können Sie Folgendes tun:

Für Readonly-Eigenschaften

public int ReadOnlyProp => 2;

Für beide schreibbare und lesbare Eigenschaften

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

In der aktuellen Version von C # (7.0) können Sie Folgendes tun: (Das Snippet zeigt eher an, wie Sie Ausdruck-gefüllte get / set-Zugriffe verwenden können, die kompakter sind, wenn Sie mit Hintergrundfeldern arbeiten)

private string label = "Default Value";

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

Manchmal benutze ich das, wenn ich nicht möchte, dass es tatsächlich in meiner db gesetzt und beibehalten wird:

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

        set { _name = value; } 
    }
}

Offensichtlich, wenn es keine Zeichenkette ist, dann könnte ich das Objekt nullbar machen (double ?, int?) Und prüfen, ob es Null ist, einen Standard zurückgeben oder den Wert zurückgeben, auf den es gesetzt ist.

Dann kann ich in meinem Repository überprüfen, ob es mein Standard ist und nicht persistieren, oder eine Hintertür einchecken, um vor dem Speichern den wahren Status des Hintergrundwertes zu sehen.

Ich hoffe, das hilft!


Meine Lösung besteht darin, ein benutzerdefiniertes Attribut zu verwenden, das die Initialisierung der Standardwerteigenschaft über die Konstante oder den Initiator des Eigenschaftstyps bereitstellt.

[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, müssen Sie eine Klasse von einem speziellen Basisklasseninitialisierer erben oder eine statische Hilfsmethode 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);
        }
    }
}

Verwendungsbeispiel:

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

Tippen Sie Prop und drücken Sie die Taste "TAB" und Visual Studio schlagen Sie folgenden Code vor,

public int MyProperty { get; set; }

nachdem Sie Modifizierer, Datentyp, Namen ändern und einfach set und Werte erhalten können.

Wenn Sie eine Variable in einer anderen Klasse verwenden müssen, können Sie sie wie folgt verwenden:

public static int MyProperty { get; set; }

Im Code können Sie eine Variable zuweisen

MyProperty=1;

in einer anderen Klasse können Sie das verwenden ,

MessageBox.Show(Classname.MyProperty);

Um dies klarzustellen, müssen Sie im Konstruktor für abgeleitete Klassenobjekte Standardwerte festlegen. Sie müssen sicherstellen, dass der Konstruktor mit dem richtigen Zugriffsmodifizierer für die Konstruktion existiert, wo er verwendet wird. Wenn das Objekt nicht instanziiert ist, dh es keinen Konstruktor hat (zB statische Methoden), kann der Standardwert durch das Feld festgelegt werden. Die Begründung hier ist, dass das Objekt selbst nur einmal erstellt wird und Sie es nicht instanziieren.

@Darren Kopp - gute Antwort, sauber und richtig. Und um es noch einmal zu wiederholen: Sie können Konstruktoren für abstrakte Methoden schreiben. Sie müssen nur auf sie von der Basisklasse zugreifen, wenn Sie den Konstruktor schreiben:

Konstruktor in der Basisklasse:

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

Konstruktor in abgeleitete / konkrete / Unterklasse:

public SubClass() : base() { }

Der Punkt hier ist, dass die Instanzvariable, die von der Basisklasse gezeichnet wird, den Namen Ihres Basisfelds begraben kann. Einstellen des aktuellen instanziierten Objektwerts mit "this" ermöglicht es Ihnen, Ihr Objekt in Bezug auf die aktuelle Instanz und die erforderlichen Berechtigungsstufen (Zugriffsmodifikatoren), an denen Sie es instanziieren, korrekt zu bilden.


Verwenden Sie den Konstruktor, da "Wenn der Konstruktor fertig ist, sollte Construction beendet werden". Eigenschaften sind wie Zustände, die Ihre Klassen besitzen. Wenn Sie einen Standardzustand initialisieren müssten, würden Sie das in Ihrem Konstruktor tun.


Wenn Sie einen Initialwert für eine Variable einfügen, wird dies implizit im Konstruktor ausgeführt.

Ich würde argumentieren, dass diese Syntax in C # bis 5 empfohlen wurde:

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 erhalten Sie eine klare Kontrolle über die Auftragswerte.

Ab C # 6 gibt es einen neuen Weg:

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

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


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




automatic-properties