Вопрос: Как вы даете C # Auto-Property значение по умолчанию?


Как вы даете C # Auto-Property значение по умолчанию? Я либо использую конструктор, либо вернусь к старому синтаксису.

Использование конструктора:

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

Есть ли способ лучше?


1393


источник


Ответы:


В C # 5 и более ранних версиях, чтобы дать автоматически реализованным свойствам значение по умолчанию, вы должны сделать это в конструкторе.

Возможность иметь инициализаторы свойств auto включена с C # 6.0. Синтаксис:

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

1534



Редактировать 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; }
}

240



Когда вы встраиваете начальное значение для переменной, это будет выполняться неявно в конструкторе в любом случае.

Я бы сказал, что этот синтаксис был наилучшей практикой в ​​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"

126



DefaultValueAttribute ТОЛЬКО работает в дизайнере vs. Он не будет инициализировать свойство для этого значения.

Видеть Атрибут DefaultValue не работает с моим Автообъектом


71



Иногда я использую это, если я не хочу, чтобы он был действительно установлен и сохранялся в моем db:

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

        set { _name = value; } 
    }
}

Очевидно, если это не строка, я могу сделать объект нулевым (double ?, int?) И проверить, является ли он нулевым, вернуть значение по умолчанию или вернуть значение, на которое оно установлено.

Затем я могу сделать чек в моем репозитории, чтобы убедиться, что он мой по умолчанию и не сохраняется, или сделать проверку бэкдор, чтобы увидеть истинный статус резервного значения, перед сохранением.

Надеюсь, это поможет!


47



Начиная с C # 6.0 , Мы можем назначить значение по умолчанию для автоматически реализованных свойств.

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

Мы также можем создать автоматическое свойство, доступное только для чтения, например:

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

Видеть: C # 6: Первые реакции, Инициализаторы для автоматически реализованных свойств - Джон Скит


20



In C# 6.0 this is a breeze!

You can do it in the Class declaration itself, in the property declaration statements.

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

13



little complete sample:

using System.ComponentModel;

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

9



My solution is to use a custom attribute that provides default value property initialization by constant or using property type initializer.

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

To use this attribute it's necessary to inherit a class from special base class-initializer or use a static helper method:

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

Usage example:

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

Output:

Item1
(X=3,Y=4)
StringValue

8



In Version of C# (6.0) & greater, you can do :

For Readonly properties

public int ReadOnlyProp => 2;

For both Writable & Readable properties

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

In current Version of C# (7.0), you can do : (The snippet rather displays how you can use expression bodied get/set accessors to make is more compact when using with backing fields)

private string label = "Default Value";

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

8



In addition to the answer already accepted, for the scenario when you want to define a default property as a function of other properties you can use expression body notation on C#6.0 (and higher) for even more elegant and concise constructs like:

public class Person{

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

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

You can use the above in the following fashion

    var p = new Person();

    p.FullName; // First Last

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

    p.FullName; // Jon Snow

In order to be able to use the above "=>" notation, the property must be read only, and you do not use the get accessor keyword.

Details on MSDN


5



In C# 6 and above you can simply use the syntax:

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

Note that to have a readonly property simply omit the set, as so:

public object Foo { get; } = bar;

You can also assign readonly auto-properties from the constructor.

Prior to this I responded as below.

I'd avoid adding a default to the constructor; leave that for dynamic assignments and avoid having two points at which the variable is assigned (i.e. the type default and in the constructor). Typically I'd simply write a normal property in such cases.

One other option is to do what ASP.Net does and define defaults via an attribute:

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


5