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

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

Используя конструктор:

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

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

25 ответов

Решение

В 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 работают ТОЛЬКО в дизайнере. Это не будет инициализировать свойство к этому значению.

См. Атрибут DefaultValue не работает с моим автоматическим свойством

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

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

        set { _name = value; } 
    }
}

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

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

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

В 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 string Name { get; set; } = "Some Name";

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

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

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

В версии C# (6.0) и выше вы можете сделать:

Для Readonly свойств

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

В C# 9.0 ключевое слово добавленоподдержкиinit- очень полезный и изощренный способ объявления автоматических свойств только для чтения :

Заявляем:

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

~ Наслаждайтесь ~ Использование:

      // Person with default name
var anonymous = new Person();
Console.WriteLine($"Hello, {anonymous.Name}!");

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

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

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

До этого я отвечал как ниже.

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

Еще один вариант - сделать то, что делает 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; }
}

Мое решение состоит в том, чтобы использовать пользовательский атрибут, который обеспечивает инициализацию свойства значения по умолчанию с помощью константы или с помощью инициализатора типа свойства.

[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

Вы можете просто поставить как это

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        SomeFlag = value;        
    }
}

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

Другие вопросы по тегам