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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2 035
0
961 674
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

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

Ответ принят как подходящий

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

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

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

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

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

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

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

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

        set { _name = value; } 
    }
}

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

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

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

return _name ?? "Default Name"; наверное даже понятнее, чем ваш

abatishchev 09.08.2010 12:11

@abatishchev: хотя это не одно и то же. Код тиглей вернет «Имя по умолчанию», если строка «» или пустая, но при использовании вашего подхода вернет «Имя по умолчанию» только в том случае, если оно равно нулю. Кроме того, обсуждается ли "??" или "IsNullOrEmpty" более понятно.

Sebastian Mach 16.12.2010 16:28

Точка является значением по умолчанию, поэтому проверка, допускающая значение NULL, отменяет точку. Ответ Кита демонстрирует это, инициализировав его в Ctor. Если это для дБ, я действительно не вижу большой разницы, чем наличие значения столбца по умолчанию и сделать его ненулевым столбцом, который будет более эффективным независимо от количества полей класса. Я не буду голосовать против, но призываю разработчиков подумать об этом, а не делать пустые / пустые проверки в ваших процедурах собственности.

Jeremy Thompson 26.12.2020 08:09

Чтобы прояснить каждый раз, когда вы вызываете свойство класса, он будет выполнять нулевую / пустую проверку, тогда как дБ будет делать это только при INSERT или UPDATE, которые обычно составляют 20% работы дБ. Вместо этого потенциально каждое строковое свойство имеет дополнительный вызов, это пустая трата циклов процессора и плохой выбор дизайна IMHO. Кроме того, теперь есть Null Ref Type, поэтому работа с nullable более распространена.

Jeremy Thompson 26.12.2020 08:17

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

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

Вы не можете преобразовать поле в свойство auto, не нарушив вызывающий код. Он может выглядеть одинаково, но сгенерированный код отличается. С автоматическими свойствами вызывающий код вызывает get_propname и set_propname за крышками, тогда как он просто обращается к полю напрямую, если это поле.

David Reis 29.07.2009 03:37

Да, это очень давно - с тех пор я пересмотрел свою позицию: stackoverflow.com/questions/205568/…

Joel Coehoorn 29.07.2009 03:53

Вы также не можете получить доступ к полю через границы домена приложения - только к свойству или методу.

Jacob Krall 06.11.2009 21:00

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

Chris Farmer 03.09.2008 07:59

И вы не можете объявить поле в интерфейсе только как свойство

yoel halb 07.08.2013 06:22

Если ваша позиция изменилась, возможно, вам стоит отредактировать / удалить этот ответ.

Zev Spitz 13.03.2020 01:18

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

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

В 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

Это не правильно; нет проблемы "двойного присваивания" с / с использованием конструктора ....

Mark Brackett 25.02.2016 22:19

Вау, это взрыв из прошлого. Я, кажется, припоминаю, что это было основано на чтении спецификации (частичный отрывок здесь: msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx). Учитывая время и количество версий (и Roslyn), этого больше не могло быть. Хотя обратная ссылка будет оценена.

Lex 28.02.2016 00:22

Назначение по умолчанию происходит автоматически, независимо от того, используете ли вы начальное значение или присваиваете в конструкторе. Существует небольшая семантическая разница - присвоение полей происходит до вызова конструктора, но присвоение null все равно произойдет. См. 10.4.5 "все поля экземпляра ... сначала инициализируются значениями по умолчанию, а затем выполняются инициализаторы поля экземпляра" msdn.microsoft.com/en-us/library/aa645757(VS.71).aspx

Mark Brackett 28.02.2016 02:47

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

using System.ComponentModel;

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

Это не сработает. DefaultValueAttribute - это просто подсказка сериализации, он не установит ShowGroup в true, потому что значение по умолчанию для любого логического значения - false.

Boris B. 29.07.2011 17:05

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

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

fire.eagle 26.05.2011 23:34

@fire: Комментирование требует 50 репутации. Голосование также требует репутации, IIRC.

Ben Voigt 03.06.2011 06:12

-1, так как это не инициализирует свойство значением по умолчанию.

Gyum Fox 07.08.2014 12:03

работает только с дизайнером, как указано во всех предыдущих ответах

KinSlayerUY 01.11.2017 18:47

Отредактировано 1/2/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; }
}

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

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

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

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

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

public SubClass() : base() { }

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

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

[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

Как указано выше, использование отражения для инициализации значений по умолчанию является медленным и излишним. Инициализируйте конструктор, используйте свойство, отличное от auto, или в C# 6 и выше используйте упрощенную нотацию, показанную в принятом ответе.

KinSlayerUY 01.11.2017 18:46

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

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

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

        SomeFlag = value;        
    }
}

Это не автоматическая собственность.

Aluan Haddad 22.02.2018 11:55

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

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

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

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

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

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

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

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

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

freefaller 20.04.2018 14:20

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

В версии 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; 
 }

Это нормально, но только второй из трех примеров является автоматическим свойством.

Aluan Haddad 22.02.2018 11:50

Также рассмотрим пример class C { public DateTime P { get; } = DateTime.Now; public DateTime Q => DateTime.Now; }, где оба свойства P и Q имеют только геттер, но поведение P и Q сильно различается!

Jeppe Stig Nielsen 13.07.2019 18:19

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

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

Jeppe Stig Nielsen 02.11.2018 11:59

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

MarkO 05.12.2018 15:27

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

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

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

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

Внимание: это не устанавливает начальное значение, а создает метод доступа get, который возвращает постоянную строку. Если значение FuelUnits установлено на другую строку, FuelUnits проигнорирует это значение и продолжит возвращать литеральную строку, определенную в get.

AjimOthy 10.07.2020 01:12

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