你如何給C#自動屬性一個默認值?




c# getter setter (18)

你如何給C#自動屬性一個默認值? 我要么使用構造函數,要么恢復到舊的語法。

使用構造函數:

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

使用正常的屬性語法 (使用默認值)

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

有沒有更好的辦法?


在C#6及以上版本中,您可以簡單地使用以下語法:

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

請注意,只有readonly屬性可以忽略該集合,如下所示:

public object Foo { get; } = bar;

您還可以從構造函數中分配readonly自動屬性。

在此之前,我回答如下。

我會避免添加一個默認的構造函數; 保留動態賦值的地方,避免賦予變量的兩個點(即類型默認值和構造函數)。 通常我會在這種情況下寫一個普通的屬性。

另一種選擇是做ASP.Net,通過屬性定義默認值:

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


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

有時我使用這個,如果我不想讓它真的被設置並保存在我的數據庫中:

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

        set { _name = value; } 
    }
}

顯然,如果它不是一個字符串,那麼我可能會使對象為空(double?,int?)並檢查它是否為null,返回一個默認值,或者返回它設置的值。

然後我可以在存儲庫中進行檢查,看看它是我的默認值並且不會保留,或者在保存前進行後門檢查以查看備份值的真實狀態。

希望有所幫助!


C#(6.0)及更高版本中 ,您可以執行以下操作:

用於Readonly屬性

public int ReadOnlyProp => 2;

對於Writable和Readable屬性

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

在當前版本的C#(7.0)中 ,您可以執行以下操作:(該代碼片段顯示瞭如何使用表達式get / set訪問器在使用後備字段時更加緊湊)

private string label = "Default Value";

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

使用構造函數是因為“當構造函數完成時,施工應該完成”。 屬性就像你的類所持有的狀態,如果你必須初始化一個默認狀態,你可以在你的構造函數中這樣做。



除了已經接受的答案之外,對於想要將默認屬性定義為其他屬性的函數時 ,您可以在C#6.0(及更高版本)上使用表達式正文表達式來獲得更優雅和簡潔的構造,如:

public class Person{

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

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

您可以按照以下方式使用上述內容

    var p = new Person();

    p.FullName; // First Last

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

    p.FullName; // Jon Snow

為了能夠使用上面的“=>”表示法,該屬性必須是只讀的,並且不使用get訪問器關鍵字。

有關MSDN詳細信息


類型道具和按下按鈕“選項卡”和Visual Studio建議您遵循代碼,

public int MyProperty { get; set; }

在您可以更改修飾符,數據類型,名稱並輕鬆分配設置並獲取值後。

如果你需要在另一個類中使用一些變量

public static int MyProperty { get; set; }

在代碼中,您可以分配變量

MyProperty=1;

在另一個課程中你可以使用這個,

MessageBox.Show(Classname.MyProperty);


初始化,使用構造函數進行初始化是不好的做法,並且會在以後導致更多突變。


一點完整的樣品:

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

在C#5及更早版本中,為了賦予自動實現的屬性默認值,您必須在構造函數中完成。

自C#6.0以來,包含了自動屬性初始值設定項的功能。 語法是:

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

我的解決方案是使用自定義屬性,通過常量或使用屬性類型初始值設定項提供默認值屬性初始化。

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

要使用此屬性,必須從特定基類初始化程序繼承某個類,或使用靜態幫助程序方法:

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

用法示例:

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

輸出:

Item1
(X=3,Y=4)
StringValue

編輯1/2/15

使用C#6,您可以直接初始化自動屬性(最終!),現在線程中還有其他答案描述了這一點。

對於C#5及以下版本:

雖然該屬性的預期用途不是實際設置屬性的值,但可以使用反射來始終設置它們......

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

當你為變量內聯一個初始值時,它將在構造函數中隱式地完成。

我認為這個語法在C#中是最佳實踐,最高可達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; }
}

這樣可以清楚地控制訂單值的分配。

從C#6開始有一個新的方法:

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

就我個人而言,如果除了汽車財產之外不會做任何事情,我根本看不出把它變成財產的問題。 只要把它作為一個領域。 這些項目的封裝優勢只是紅鯡魚,因為它們背後沒有任何封裝。 如果您需要更改底層實現,您仍然可以自由地將它們重構為屬性,而不會破壞任何相關代碼。

嗯......也許這將成為它後面自己問題的主題





automatic-properties