如何给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;
    }
}

有更好的方法吗?


当前回答

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

[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

其他回答

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

从C#6.0开始,我们可以为自动实现的财产指定默认值。

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

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

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

参见:C#6:第一反应,自动实现财产的初始化程序-Jon Skeet

这已经过时了,我的立场已经改变了。我将把最初的答案留给子孙后代。


就我个人而言,如果你不打算在汽车产业之外做任何事情,我根本不认为把它变成一个产业有什么意义。把它当作一块场地。这些项目的封装优势只是红色的鲱鱼,因为它们背后没有什么可封装的。如果您需要更改底层实现,您仍然可以将其重构为财产,而不会破坏任何依赖代码。

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

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

@达伦·科普(Darren Kopp)-回答不错,干净利落,正确无误。重申一下,您可以为抽象方法编写构造函数。您只需在编写构造函数时从基类访问它们:

基类构造函数:

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

派生/具体/子类的构造函数:

public SubClass() : base() { }

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

private string name;
public string Name 
{
    get 
    {
        if(name == null)
        {
            name = "Default Name";
        }
        return name;
    }
    set
    {
        name = value;
    }
}