c# - 你如何给C#自动属性一个默认值?




automatic-properties (19)

您是否尝试过使用http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspxShouldSerialize和Reset方法与构造函数结合使用? 如果你正在创建一个可能出现在设计器表面或属性网格中的类,我觉得这两种方法中的一种是必需的。

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

有没有更好的办法?



澄清,是的,你需要在类派生对象的构造函数中设置默认值。 您将需要确保构造函数存在与正确的访问修饰符在建筑使用。 如果对象没有实例化,例如它没有构造函数(例如静态方法),那么可以通过该字段设置默认值。 这里的推理是对象本身只会被创建一次,并且你没有实例化它。

@Darren Kopp - 很好的答案,干净,正确。 并且要重申,您可以为抽象方法编写构造函数。 编写构造函数时,只需从基类访问它们即可:

基类的构造函数:

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

Derived / Concrete / Sub-Class的构造函数:

public SubClass() : base() { }

这里的要点是,从基类中绘制的实例变量可能会隐藏您的基本字段名称。 使用“this”设置当前实例化的对象值。 将允许您针对当前实例正确地形成对象,并在您要实例化它的位置所需的权限级别(访问修饰符)。


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

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

我认为这样做会为你带来SomeFlag默认值为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 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详细信息


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

一点完整的样品:

using System.ComponentModel;

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

就我个人而言,如果除了汽车财产之外不会做任何事情,我根本看不出把它变成财产的问题。 只要把它作为一个领域。 这些项目的封装优势只是红鲱鱼,因为它们背后没有任何封装。 如果您需要更改底层实现,您仍然可以自由地将它们重构为属性,而不会破坏任何相关代码。

嗯......也许这将成为它后面自己问题的主题


有时我使用这个,如果我不想让它真的被设置并保存在我的数据库中:

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中,这是一件轻而易举的事!

您可以在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;
    }
}

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


初始化一致,使用构造函数进行初始化是不好的做法,并且会在以后导致更多的突变。


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


simple code with LINQ

string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

EDIT : as commented below, it is not a good way.

but you can still use it to understand LINQ with a more appropriate coding :

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();






c# automatic-properties