Как лучше всего задать автоматическому свойству C # начальное значение?

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

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


person bentford    schedule 02.09.2008    source источник
comment
попробуйте это: public int _X {set; получить;} = _x;   -  person گلی    schedule 18.07.2021


Ответы (22)


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

Начиная с C # 6.0, вы можете указать начальное значение в строке. Синтаксис:

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

DefaultValueAttribute предназначен для используется дизайнером VS (или любым другим потребителем) для указания значения по умолчанию, а не начального значения. (Даже если в спроектированном объекте начальное значение является значением по умолчанию).

Во время компиляции DefaultValueAttribute не повлияет на сгенерированный IL, и он не будет прочитан для инициализации свойства этим значением (см. Атрибут DefaultValue не работает с моим автоматическим свойством).

Примером атрибутов, влияющих на IL, являются _4 _, _5 _, ...

person Darren Kopp    schedule 02.09.2008

Отредактировано 15 января

C # 6:

С 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; }
}
person Chuck Rostance    schedule 22.06.2011

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

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

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

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

        set { _name = value; } 
    }
}

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

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

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

person crucible    schedule 02.09.2008
comment
return _name ?? "Default Name"; наверное даже более понятно, что ваш - person abatishchev; 09.08.2010
comment
@abatishchev: хотя это не одно и то же. Код тиглей вернет имя по умолчанию, если строка имеет значение или значение null, но при использовании вашего подхода имя по умолчанию будет возвращено только в том случае, если оно равно нулю. Кроме того, обсуждается ли ?? или IsNullOrEmpty более понятен. - person Sebastian Mach; 16.12.2010
comment
Точка является значением по умолчанию, поэтому проверка, допускающая значение NULL, отменяет точку. Ответ Кита демонстрирует это, инициализировав его в Ctor. Если это для дБ, я действительно не вижу большой разницы, чем наличие значения столбца по умолчанию и сделать его ненулевым столбцом, который будет более эффективным независимо от количества полей класса. Я не буду голосовать против, но призываю разработчиков подумать об этом, а не делать пустые / пустые проверки в ваших процедурах собственности. - person Jeremy Thompson; 26.12.2020
comment
Чтобы прояснить каждый раз, когда вы вызываете свойство класса, он будет выполнять нулевую / пустую проверку, тогда как дБ будет делать это только при INSERT или UPDATE, которые обычно составляют 20% работы дБ. Вместо этого потенциально каждое строковое свойство имеет дополнительный вызов, это пустая трата циклов процессора и плохой выбор дизайна IMHO. Кроме того, теперь есть Null Ref Type, поэтому работа с nullable более распространена. - person Jeremy Thompson; 26.12.2020

В 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;
    }
}
person Shiva    schedule 25.07.2016
comment
У меня еще нет C # 6.0, и я проверял, какая версия мне нужна для значений по умолчанию в автоматических свойствах. Устраняет ли C # 6.0 необходимость иметь { get; set; } или { get; private set; }, иначе установка значения будет заблокирована компилятором? - person freefaller; 20.04.2018

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

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

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

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

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

person Habib    schedule 29.04.2014

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

Для свойств только для чтения

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; 
 }
person ANewGuyInTown    schedule 15.03.2017
comment
Это нормально, но только второй из трех примеров является автоматическим свойством. - person Aluan Haddad; 22.02.2018
comment
Также рассмотрим пример class C { public DateTime P { get; } = DateTime.Now; public DateTime Q => DateTime.Now; }, где оба свойства P и Q имеют только геттер, но поведение P и Q сильно различается! - person Jeppe Stig Nielsen; 13.07.2019

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

person brakeroo    schedule 30.10.2016

В 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

person Lex    schedule 04.09.2008
comment
Это не правильно; нет проблемы двойного присваивания с использованием конструктора .... - person Mark Brackett; 25.02.2016
comment
Вау, это взрыв из прошлого. Я припоминаю, что это было основано на прочтении спецификации (частичный отрывок здесь: msdn.microsoft.com/en-us/library/aa645756 (v = vs.71) .aspx). Учитывая время и количество версий (и Roslyn), этого больше не могло быть. Хотя обратная ссылка будет оценена. - person Lex; 28.02.2016
comment
Назначение по умолчанию происходит автоматически, независимо от того, используете ли вы начальное значение или присваиваете в конструкторе. Существует небольшая семантическая разница - присвоение полей происходит до вызова конструктора, но присвоение null все равно произойдет. См. 10.4.5. Все поля экземпляра ... сначала инициализируются значениями по умолчанию, а затем инициализаторы полей экземпляра выполняются msdn.microsoft.com/en-us/library/aa645757 (VS.71) .aspx - person Mark Brackett; 28.02.2016

небольшой полный образец:

using System.ComponentModel;

private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
    get { return bShowGroup; }
    set { bShowGroup = value; }
}
person ghiboz    schedule 17.06.2010
comment
Это не сработает. DefaultValueAttribute - это просто подсказка сериализации, она не установит ShowGroup в true, потому что значение по умолчанию для любого логического значения - false. - person Boris B.; 29.07.2011

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

[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
person introspected    schedule 17.01.2013
comment
Как указано выше, использование отражения для инициализации значений по умолчанию является медленным и излишним. Инициализируйте конструктор, используйте свойство, отличное от auto, или в C # 6 и выше используйте упрощенную нотацию, показанную в принятом ответе. - person KinSlayerUY; 01.11.2017

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

Объявляем:

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

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

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


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


// 3. Attempt to re-assignment Name
me.Name = "My fake"; 
// > Compilation error: Init-only property can only be assigned in an object initializer
person codez0mb1e    schedule 24.05.2021

В конструкторе. Конструктор предназначен для инициализации членов данных.

person RayLoveless    schedule 18.07.2016

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

public sealed  class Employee
{
    public int Id { get; set; } = 101;
}
person Sunil Dhappadhule    schedule 18.02.2019

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

person OwenP    schedule 02.09.2008

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

@ Даррен Копп - хороший ответ, чистый и правильный. И, повторюсь, вы МОЖЕТЕ писать конструкторы для абстрактных методов. Вам просто нужно получить к ним доступ из базового класса при написании конструктора:

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

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

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

public SubClass() : base() { }

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

person Zack Jannsen    schedule 31.07.2012

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

person Preet Singh    schedule 11.01.2016

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

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

person Joel Coehoorn    schedule 03.09.2008
comment
@ Джоэл: привязка данных и другие инструменты, основанные на отражении, часто ожидают свойства, а не поля. - person Chris Farmer; 03.09.2008
comment
Вы не можете преобразовать поле в свойство auto, не нарушив вызывающий код. Он может выглядеть одинаково, но сгенерированный код отличается. С автоматическими свойствами вызывающий код вызывает get_propname и set_propname за крышками, тогда как он просто обращается к полю напрямую, если это поле. - person David Reis; 29.07.2009
comment
Да, это очень давно. С тех пор я изменил свою позицию: stackoverflow.com/questions/205568/ - person Joel Coehoorn; 29.07.2009
comment
Вы также не можете получить доступ к полю через границы домена приложения - только к свойству или методу. - person Jacob Krall; 06.11.2009
comment
И вы не можете объявить поле в интерфейсе только как свойство - person yoel halb; 07.08.2013
comment
Если ваша позиция изменилась, возможно, вам стоит отредактировать / удалить этот ответ. - person Zev Spitz; 13.03.2020

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

//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";
}
person Jesse Adam    schedule 25.05.2020
comment
Предупреждение: это не устанавливает начальное значение, а создает метод доступа get, который возвращает постоянную строку. Если значение FuelUnits установлено на другую строку, FuelUnits проигнорирует это значение и продолжит возвращать литеральную строку, определенную в get. - person AjimOthy; 10.07.2020

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

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

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

        SomeFlag = value;        
    }
}
person user3076134    schedule 06.12.2013
comment
Это не автоматическая собственность. - person Aluan Haddad; 22.02.2018

person    schedule
comment
Я думаю, что задающий вопрос хотел автоматическое свойство, то есть неабстрактное свойство в классе или структуре, где вы используете только get; с точкой с запятой (часто в сочетании с set;), чтобы указать, что компилятор должен автоматически сгенерировать тело get аксессора. - person Jeppe Stig Nielsen; 02.11.2018
comment
Кроме того, этот код имеет побочный эффект возврата к значению по умолчанию, если явно задано значение null. - person MarkO; 05.12.2018

person    schedule
comment
Добро пожаловать в Stack Overflow! Просто чтобы вы знали, поднимать старый вопрос, как этот, обычно не одобряют, если у вас нет хорошей новой информации. Однако в этом случае несколько других уже опубликовали информацию об атрибуте DefaultValue. Если кто-то уже опубликовал то, что вы собирались сказать, более целесообразно проголосовать за него, щелкнув стрелку вверх над числом рядом с его ответом. - person fire.eagle; 26.05.2011
comment
@fire: Комментирование требует 50 репутации. Голосование также требует репутации, IIRC. - person Ben Voigt; 03.06.2011
comment
-1, поскольку это не инициализирует свойство значением по умолчанию. - person Gyum Fox; 07.08.2014
comment
работает только с дизайнером, как указано во всех предыдущих ответах - person KinSlayerUY; 01.11.2017