给C#自动属性初始值的最佳方法是什么?

如何给C#自动属性一个初始值?

我要么使用构造函数,要么恢复到旧语法。

使用构造函数:

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

使用普通属性语法(初始值)

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

有没有更好的办法?

1173109 次浏览

您是否尝试过将默认值属性应该序列化和重置方法与构造函数结合使用?如果您要创建可能出现在设计器表面或属性网格中的类,我觉得这两种方法之一是必要的。

在C#5及更早版本中,要为自动实现的属性提供初始值,您必须在构造函数中执行此操作。

c#6.0开始,您可以在线指定初始值。语法是:

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

#0旨在由VS设计器(或任何其他消费者)用于指定默认值,而不是初始值。(即使在设计对象中,初始值也是默认值)。

在编译时DefaultValueAttribute不会影响生成的IL,也不会读取它来将属性初始化为该值(参见DefaultValue属性不适用于我的Auto Property)。

影响IL的属性示例有#0#1、…

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

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

显然,如果它不是字符串,那么我可能会使对象为空(双精度?,int?)并检查它是否为空,返回默认值,或返回它设置的值。

然后我可以在我的存储库中进行检查,看看它是否是我的默认值而不是持久化,或者在保存之前进行后门签入以查看支持值的真实状态。

希望有帮助!

这个问题已经过时了,我的立场也变了。我把原来的答案留给后人。


就我个人而言,如果你除了自动属性之外什么都不做,我看不出让它成为属性有什么意义。就把它作为一个字段吧。这些项目的封装好处只是转移注意力,因为它们背后没有什么可以封装的。如果你需要更改底层实现,你仍然可以自由地将它们重构为属性,而不会破坏任何依赖代码。

嗯…也许这将是它自己的问题稍后的主题

当您内联变量的初始值时,无论如何都会在构造函数中隐式完成。

我认为这种语法是C#到5的最佳实践:

class Person{public Person(){//do anything before variable assignment
//assign initial valuesName = "Default Name";
//do anything after variable assignment}public string Name { get; set; }}

因为这使您可以清楚地控制订单值的分配。

从C#6开始,有一种新的方法:

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

在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

小完整样本:

using System.ComponentModel;
private bool bShowGroup ;[Description("Show the group table"), Category("Sea"),DefaultValue(true)]public bool ShowGroup{get { return bShowGroup; }set { bShowGroup = value; }}
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/15

c#6

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

澄清一下,是的,您需要在类派生对象的构造函数中设置默认值。您需要确保构造函数存在,并使用正确的访问修饰符进行构造。如果对象没有实例化,例如它没有构造函数(例如静态方法),那么可以由字段设置默认值。这里的原因是对象本身只会被创建一次,而您不会实例化它。

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

基类的构造函数:

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

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

public SubClass() : base() { }

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

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

[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

我认为这将为雅做一些标志的默认值为false。

private bool _SomeFlagSet = false;public bool SomeFlag{get{if (!_SomeFlagSet)SomeFlag = false;
return SomeFlag;}set{if (!_SomeFlagSet)_SomeFlagSet = true;
SomeFlag = value;}}

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

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

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

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

见:C#6:第一反应,自动实现属性的初始化器-作者:Jon Skeet

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

使用构造函数,因为“当构造函数完成时,构造应该完成”。属性就像你的类持有的状态,如果你必须初始化默认状态,你会在你的构造函数中这样做。

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

在C#6.0中,这是一件轻而易举的事情!

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

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(及更高版本)上使用表达式正文符号来实现更优雅和简洁的构造,例如:

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

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

对于只读属性

public int ReadOnlyProp => 2;

对于可写和可读属性

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;}
private string name;public string Name{get{if(name == null){name = "Default Name";}return name;}set{name = value;}}

你可以这样简单地说

public sealed  class Employee{public int Id { get; set; } = 101;}

我知道这是一个古老的问题,但当我在寻找如何拥有一个默认值,该值可以通过覆盖选项继承时,我想出了

//base classpublic class Car{public virtual string FuelUnits{get { return "gasoline in gallons"; }protected set { }}}//derivedpublic class Tesla : Car{public override string FuelUnits => "ampere hour";}

c#9.0中是init关键字中的增加支持-非常有用,非常复杂的方式用于声明只读自动属性

宣告:

class Person{public string Name { get; init; } = "Anonymous user";}

~享受~使用:

// 1. Person with default namevar anonymous = new Person();Console.WriteLine($"Hello, {anonymous.Name}!");// > Hello, Anonymous user!

// 2. Person with assigned valuevar me = new Person { Name = "@codez0mb1e"};Console.WriteLine($"Hello, {me.Name}!");// > Hello, @codez0mb1e!

// 3. Attempt to re-assignment Nameme.Name = "My fake";// > Compilation error: Init-only property can only be assigned in an object initializer