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

Как вы даете авто-свойству 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;
    }
}

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

21 ответов


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

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

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

изменить 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; }
}

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

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

атрибут defaultvalueattribute работать только в vs дизайнер. Он не будет инициализировать объект с этим значением.

посмотреть атрибут DefaultValue не работает с моим свойством Auto


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

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

        set { _name = value; } 
    }
}

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

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

надеюсь, что помогает!


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

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

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

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

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


В 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) & больше, вы можете сделать :

для свойств Readonly

public int ReadOnlyProp => 2;

для обоих записываемых и читаемых свойств

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

В текущей версии C# (7.0), вы можете сделать : (фрагмент скорее отображает, как вы можете использовать выражение bodied get/set accessors, чтобы сделать более компактным при использовании с полями поддержки)

private string label = "Default Value";

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

мало полный пример:

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

в дополнение к уже принятому ответу, для сценария, когда вы хотите определить свойство по умолчанию как функции других свойств, которые вы можете использовать выражения обозначения кузова на 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 accessor не используется.

подробнее о MSDN


В C# 6 и выше, вы можете просто использовать следующий синтаксис:

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

обратите внимание, что у readonly свойство просто опустить множество, как так:

public object Foo { get; } = bar;

вы также можете назначить readonly auto-свойства из конструктора.

до этого я ответил ниже.

Я бы избегал добавления значения по умолчанию в конструктор; оставьте это для динамических назначений и избегайте двух точек, в которых назначается переменная (т. е. тип default и в конструктор.) Обычно в таких случаях я просто пишу нормальное свойство.

еще один вариант-сделать то, что ASP.Net делает и определяет значения по умолчанию с помощью атрибута:

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


в конструкторе. Цель конструктора-инициализировать его члены данных.


вы пробовали использовать DefaultValueAttribute или ShouldSerialize и методы сброса в сочетании с конструктором? Я чувствую, что один из этих двух методов необходим, если вы создаете класс, который может отображаться на поверхности конструктора или в сетке свойств.


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

лично я не вижу смысла делать это свойство вообще, если вы не собираетесь ничего делать вообще за пределами авто-собственности. Просто оставь это как поле. Преимущество инкапсуляции для этого элемента-это просто красные селедки, потому что за ними нечего инкапсулировать. Если вам когда-либо понадобится изменить базовую реализацию, вы по-прежнему можете рефакторировать их как свойства, не нарушая зависимый код.

Мда... может быть, это будет предметом его собственного вопрос позже


разъяснить, да, вам нужно установить значения по умолчанию в конструкторе класса, производного объектов. Вам нужно будет убедиться, что конструктор существует с соответствующим модификатором доступа для построения, где используется. Если объект не создан, например, у него нет конструктора (например, статические методы), то значение по умолчанию может быть установлено полем. Аргументацией здесь является то, что сам объект будет создан только один раз и вы не инстанцировать его.

@Darren Kopp-хороший ответ, чисто и правильно. И чтобы повторить, вы можете написать конструкторы для абстрактных методов. Вам просто нужно получить к ним доступ из базового класса при написании конструктора:

конструктор в базовом классе:

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

конструктор в производном / конкретном / подклассе:

public SubClass() : base() { }

дело в том, что переменная экземпляра взяты из базового класса может похоронить ваше имя базового поля. Установка текущего значения экземпляра объекта с помощью " this."позволит вам правильно сформируйте свой объект относительно текущего экземпляра и требуемых уровней разрешений (модификаторов доступа), где вы его создаете.


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


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

Я думаю, что это сделает это для ya, давая SomeFlag значение по умолчанию false.

private bool _SomeFlagSet = false;
public bool SomeFlag
{
    get
    {
        if (!_SomeFlagSet)
            SomeFlag = false;        

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

        SomeFlag = value;        
    }
}

инициализировать в строке, используя конструкторы для инициализации-плохая практика и приведет к более разрушительным изменениям позже.