关于自动属性:如何给C自动属性一个默认值? Auto-Property

How do you give a C# Auto-Property a default value?

如何给C auto属性一个默认值?我要么使用构造函数,要么恢复到旧的语法。

使用构造函数:

1
2
3
4
5
6
7
8
class Person
{
    public Person()
    {
        Name ="Default Name";
    }
    public string Name { get; set; }
}

使用普通属性语法(使用默认值)

1
2
3
4
5
6
7
8
9
10
11
12
private string name ="Default Name";
public string Name
{
    get
    {
        return name;
    }
    set
    {
        name = value;
    }
}

有更好的方法吗?


在C 5和更早的版本中,为了给自动实现的属性一个默认值,您必须在构造函数中这样做。

自C 6.0以来,包含自动属性初始值设定项的功能。语法是:

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


2015年1月2日编辑

C 6:

使用C 6,您可以直接初始化自动属性(最后!)现在,在描述这个问题的线索中还有其他答案。

C 5及以下:

虽然属性的预期用途不是实际设置属性的值,但是您可以使用反射来始终设置它们…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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的最佳实践:

1
2
3
4
5
6
7
8
9
10
11
12
13
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开始,有一种新的方法:

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


默认值属性仅在vs设计器中有效。它不会将属性初始化为该值。

请参见默认值属性不使用我的自动属性


有时我使用这个,如果我不希望它在我的数据库中被实际设置和持久化:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person
{
    private string _name;
    public string Name
    {
        get
        {
            return string.IsNullOrEmpty(_name) ?"Default Name" : _name;
        }

        set { _name = value; }
    }
}

显然,如果它不是字符串,那么我可以使对象可以为空(double?,int?)并检查它是否为空,返回一个默认值,或者返回它设置的值。

然后我可以在我的存储库中进行一次检查,以查看它是否是我的默认值并且不持久,或者在保存之前进行一次后门检入以查看备份值的真实状态。

希望有帮助!


从C 6.0开始,我们可以将默认值分配给自动实现的属性。

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

我们还可以创建只读的自动实现属性,如:

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

参见:c 6:第一个反应,自动实现属性的初始值设定项-由jon skeet


在C 6.0中,这是一种轻风!

您可以在Class声明本身、属性声明语句中进行此操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
    }
}


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

用于只读属性

1
public int ReadOnlyProp => 2;

对于可写和可读属性

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

在C(7.0)的当前版本中,您可以这样做:(代码段显示了如何使用表达式bodied get/set访问器,使其在与支持字段一起使用时更紧凑)

1
2
3
4
5
6
7
8
private string label ="Default Value";

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


除了已经接受的答案外,对于要将默认属性定义为其他属性的函数的场景,您可以在C 6.0(及更高版本)上使用表达式体表示法来实现更优雅、更简洁的构造,例如:

1
2
3
4
5
6
7
public class Person{

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

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

您可以按以下方式使用上面的内容

1
2
3
4
5
6
7
8
    var p = new Person();

    p.FullName; // First Last

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

    p.FullName; // Jon Snow

为了能够使用上面的"=>"符号,属性必须是只读的,并且不使用get accessor关键字。

关于MSDN的细节


小完整样本:

1
2
3
4
5
6
7
8
9
using System.ComponentModel;

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


我的解决方案是使用自定义属性,该属性通过常量或使用属性类型初始值设定项提供默认值属性初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
[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];
    }
}

要使用此属性,必须从特殊的基类初始值设定项继承类或使用静态帮助器方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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);
        }
    }
}

使用实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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);
}

输出:

1
2
3
Item1
(X=3,Y=4)
StringValue


在C 6及以上版本中,您只需使用以下语法:

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

请注意,要使用readonly属性,只需省略集合,如下所示:

1
public object Foo { get; } = bar;

还可以从构造函数中分配readonly自动属性。

在此之前,我的回答如下。

我将避免向构造函数中添加默认值;将其留给动态赋值,并避免在变量被赋值时有两个点(即类型默认值和构造函数中)。在这种情况下,通常我只写一个普通属性。

另一个选项是执行ASP.NET的操作,并通过属性定义默认值:

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


在构造函数中。构造函数的目的是初始化它的数据成员。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private string name;
public string Name
{
    get
    {
        if(name == null)
        {
            name ="Default Name";
        }
        return name;
    }
    set
    {
        name = value;
    }
}


您是否尝试过与构造函数一起使用defaultvalueattribute或shouldserialize和reset方法?我觉得这两个方法中的一个是必要的,如果你正在创建一个类,它可能会出现在设计器图面或属性网格中。


1
2
3
4
5
6
public Class ClassName{
    public int PropName{get;set;}
    public ClassName{
        PropName=0;  //Default Value
    }
}

就我个人而言,如果你不打算做任何超越汽车业的事情,我根本就不认为这是一种财产。把它当作一个场。这些项目的封装好处只是红鲱鱼,因为它们后面没有什么可以封装的。如果您需要更改底层实现,您仍然可以自由地将它们重构为属性,而不破坏任何依赖代码。

隐马尔可夫模型。。。也许这将是以后它自己的问题的主题


要澄清,是的,您需要在类派生对象的构造函数中设置默认值。您将需要确保构造函数存在,并在使用时为构造提供适当的访问修饰符。如果对象没有实例化,例如它没有构造函数(例如静态方法),那么可以通过字段设置默认值。这里的理由是对象本身只创建一次,而您不实例化它。

@Darren Kopp-回答正确、干净、正确。重复一下,您可以为抽象方法编写构造函数。在编写构造函数时,只需要从基类访问它们:

基类上的构造函数:

1
2
3
4
public BaseClassAbstract()
{
    this.PropertyName ="Default Name";
}

派生/混凝土/子类的构造函数:

1
public SubClass() : base() { }

这里的要点是,从基类中提取的实例变量可能会隐藏您的基字段名。使用"this."设置当前实例化的对象值将允许您根据当前实例和所需的权限级别(访问修饰符)正确地构造对象。


你可以这样简单地放

1
2
3
4
    public sealed  class Employee
{
    public int Id { get; set; } = 101;
}


使用构造函数是因为"当构造函数完成时,应该完成构造"。属性类似于类所持有的状态,如果必须初始化默认状态,则可以在构造函数中这样做。


1
2
3
4
5
6
7
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; }
}


我想这对你来说是个错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private bool _SomeFlagSet = false;
public bool SomeFlag
{
    get
    {
        if (!_SomeFlagSet)
            SomeFlag = false;        

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

        SomeFlag = value;        
    }
}


在行中初始化,使用构造函数初始化是不好的做法,稍后会导致更多的中断更改。