Каков наилучший способ дать авто-свойству 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;
    }
}

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

2.09.2008 21:29:41
Это вводит в заблуждение, даже в IntelliSense говорится: «Устанавливает значение по умолчанию для свойства», но в MSDN говорится: «DefaultValueAttribute не будет вызывать автоматическую инициализацию элемента со значением атрибута. Вы должны установить начальное значение в твой код. ", Ург!
Chris 22.02.2010 05:11:18
Это одно из немногих мест, где vb.net имеет явный верх, они могут устанавливать значения по умолчанию для свойств в определении.
Blindy 9.08.2010 08:35:07
Почему вы не хотите возвращать свойство с инициализированным полем? Вот как компилятор реализует автоматические свойства в любом случае. Также явное поле имеет то преимущество, что вы можете объявить его readonly.
finnw 9.11.2010 12:52:11
@finnw IMO - это улучшение читабельности кода.
Keith 17.11.2011 02:26:18
Это единственное, что мне нравится в VB.NET, а не на C #. Public Property MyName As String = "Default Name"
Alex Yeung 3.12.2012 07:21:12
21 ОТВЕТ
РЕШЕНИЕ

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

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

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

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

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

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

2261
11.10.2019 15:12:13
абстрактные классы обычно имеют защищенные конструкторы.
Ludovic Chabant 29.07.2011 19:06:31
абстрактные классы обычно имеют любую доступность, которую вы им предоставляете. если вы не указываете конструктор, у вас всегда есть общедоступный конструктор по умолчанию
Darren Kopp 29.07.2011 23:04:40
@CallMeLaNN вызов: base () в вашем конкретном классе, чтобы построить его базу (аннотация)
Guillaume Massé 8.09.2011 21:00:56
Конструкторам абстрактных классов никогда не следует предоставлять открытый доступ, поскольку их никогда нельзя создать. Это будет нарушением FxCop (надеюсь, вы его используете) и нарушением Руководства по разработке .NET Framework - amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/…
Dave Black 8.02.2012 14:16:47
@HankSchultz нет, инициализатор объекта - это просто сахар, который делает компилятор. что на самом деле выбрасывается так: var person = new Person(); persion.Name = "My Value";конструктор всегда запускается первым
Darren Kopp 19.06.2013 23:07:18

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

3
2.09.2008 21:38:10
@Hans: они работают «в реальной жизни», но только для установки значения по умолчанию (например, это влияет на сериализацию XML). Здесь требуется не «значение по умолчанию», а «начальное значение».
Ben Voigt 3.06.2011 02:09:37

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

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

        set { _name = value; } 
    }
}

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

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

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

62
2.09.2008 23:07:27
return _name ?? "Default Name";наверное даже более понятно что твой
abatishchev 9.08.2010 08:11:15
@abatishchev: хотя это не то же самое. Код Crucibles будет возвращать «Имя по умолчанию», если строка «» или ноль, но при использовании вашего подхода будет возвращено «Имя по умолчанию», только если оно нулевое. Кроме того, обсуждается ли "??" или "IsNullOrEmpty" более понятно.
Sebastian Mach 16.12.2010 13:28:27
@phresnel: Если значение свойства может быть "" и оно равно нулю, то вы правы. В противном случае "" является значимым значением, и мой код лучше
abatishchev 17.12.2010 06:51:30
private string _name = "Default Name"; public string Name { get { return _name; } set { _name = value; } }
Gilbert 24.05.2016 13:40:40
@ Гилберт - вы повторили один из вариантов кода, показанных в вопросе. Ответ Crucible специально для случая «Я не хочу, чтобы значение по умолчанию сохранялось в моей БД». То есть он хочет иметь возможность определить в другом месте, записан ли _name или все еще имеет значение null. [Его код записи или сохранения проверяет _nameналичие нуля, пропускает его написание.]
ToolmakerSteve 28.01.2018 21:31:25

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

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

1
3.09.2008 03:43:20
@ Joel : привязка данных и другие инструменты на основе отражения часто ожидают свойства, а не поля.
Chris Farmer 3.09.2008 03:59:35
Вы не можете преобразовать поле в свойство auto, не нарушая вызывающий код. Это может выглядеть одинаково, но сгенерированный код отличается. С автоматическими свойствами вызывающий код вызывает get_propname и set_propname за обложками, тогда как он просто обращается к полю напрямую, если это поле.
David Reis 28.07.2009 23:37:34
Да, это очень старо - с тех пор я пересмотрел свою позицию: stackoverflow.com/questions/205568/…
Joel Coehoorn 28.07.2009 23:53:54
Вы не можете получить доступ к полю через границы AppDomain - только свойство или метод.
Jacob Krall 6.11.2009 18:00:12
И вы не можете объявить поле в интерфейсе только свойством
yoel halb 7.08.2013 02:22:46

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

Я бы сказал, что этот синтаксис был лучшей практикой в ​​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";
164
6.11.2019 09:28:52
Лучше всего, если конструкторы должны инициализироваться разными способами (через несколько конструкторов). Если все они инициализируются одинаково, разве вы не предлагаете плохую практику, если я также хочу Person (строковое имя), а затем позже я добавляю свойство int ID и у меня есть еще один конструктор Person (строковое имя, int id)? Нарушение открытого для расширения, закрытого для модификации. Я утверждаю, что лучше всего инициализировать в строке, если все конструкторы инициализируют элемент одинаково.
dbobrowski 13.09.2012 19:12:59
@dbobrowski Если бы у меня было несколько конструкторов, я бы использовал public Person(string name, int id) : this()синтаксис, но у вас есть точка зрения. Это дает вам более точный контроль того, когда именно свойства инициализируются, за счет упрощения обслуживания встроенного параметра.
Keith 8.03.2013 16:35:31
@ Я бы предпочел public Person():this("Default Name"), а не устанавливать имя дважды.
ANeves 31.01.2014 17:43:31
если вам нужно запустить один и тот же код в нескольких местах, вы не прибегаете к рефлексии и странным атрибутам, о которых никто никогда не слышал. Вы извлекаете вспомогательный метод, или в действительно сложных местах создаете фабрику (или просто полностью перепроектируете / разбиваете свой класс, поскольку он, вероятно, слишком сложен)
sara 14.12.2015 07:40:45

В 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

9
17.06.2017 15:43:26
Это не верно; нет проблемы "двойного назначения" с использованием конструктора ....
Mark Brackett 25.02.2016 19:19:00
Вау, это взрыв из прошлого. Кажется, я помню, что это было основано на чтении спецификации (частичная выдержка здесь: msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx ). Учитывая время и количество версий (и Roslyn), это уже не может иметь место. Хотя встречная ссылка была бы оценена.
Lex 27.02.2016 21:22:26
Назначение по умолчанию происходит автоматически независимо от того, используете ли вы начальное значение или присваиваете конструктор. Есть небольшое семантическое различие - назначения полей происходят до вызовов конструктора - но нулевое назначение все равно будет происходить. См. 10.4.5 «Все поля экземпляра ... сначала инициализируются в значения по умолчанию, а затем выполняются инициализаторы поля экземпляра» msdn.microsoft.com/en-us/library/aa645757(VS.71).aspx
Mark Brackett 27.02.2016 23:47:12

маленький полный образец:

using System.ComponentModel;

private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
    get { return bShowGroup; }
    set { bShowGroup = value; }
}
11
21.11.2016 11:14:17
Это не сработает. DefaultValueAttributeэто просто сериализация намек, он не будет установлен ShowGroupв trueтак как значение по умолчанию для любого булева является false.
Boris B. 29.07.2011 13:05:14
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; }
}
0
31.07.2014 13:55:16
Добро пожаловать в переполнение стека! Точно так же, как вы знаете, если вспомнить старый вопрос, подобный этому, обычно не одобряется, если у вас нет какой-либо хорошей новой информации. Однако в этом случае несколько других уже опубликовали информацию об атрибуте DefaultValue. Если кто-то уже опубликовал то, что вы собирались сказать, более целесообразно объявить его, нажав на стрелку вверх над номером рядом с его ответом.
fire.eagle 26.05.2011 19:34:55
@fire: комментирование требует 50 репутации. Голосование также требует репутации IIRC.
Ben Voigt 3.06.2011 02:12:48
-1, поскольку это не инициализирует свойство значением по умолчанию.
Gyum Fox 7.08.2014 08:03:59
работает только над дизайнером, как указано во всех предыдущих ответах
KinSlayerUY 1.11.2017 15:47:29

Отредактировано 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; }
}
292
31.01.2019 06:21:23
Да, это ответ: [System.ComponentModel.DefaultValue (GiveAnyTypeOfDefaultValueHere)]
Tamilmaran 10.02.2012 05:44:53
+1 за изобретательность, но это может быть очень медленно. Представьте newсебе кучу элементов во внутреннем цикле, не понимая, что конструкторы используют отражение ...
Patrick M 1.11.2012 20:04:46
Если базовый класс использует статический конструктор для загрузки атрибутов и значений в словарь, для каждого класса нет накладных расходов!
Gayot Fow 4.07.2013 19:16:45
Вы рекомендуете действительно плохую вещь. Это довольно медленно и вводит рефлексию в довольно простой класс. Если бы он не был таким медленным, было бы хорошо использовать какое-нибудь переплетение с таким атрибутом (PostSharp, Fody и т. Д.), Но производительность ...
Grigory 21.08.2013 13:03:00
Только хорошо для дизайнера VS и даже не во всех случаях (например, asp.net), во всяком случае ... это ничего не сделает во время выполнения.
G.Y 25.08.2013 08:08:11

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

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

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

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

Конструктор в Производных / Бетонах / Подклассах:

public SubClass() : base() { }

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

2
7.06.2013 14:26:41

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

[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
10
18.01.2013 07:52:54
Как указано выше, использование отражения для инициализации значений по умолчанию является медленным и избыточным. Инициализируйте в конструкторе, используйте неавтоматическое свойство или на c # 6 и выше, используйте упрощенную запись, показанную в принятом ответе
KinSlayerUY 1.11.2017 15:46:08

Я думаю, что это сделало бы это для 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;        
    }
}
-2
6.12.2013 21:50:59
Это не авто-собственность.
Aluan Haddad 22.02.2018 08:55:19

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

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

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

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

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

40
24.07.2015 17:22:22
public Class ClassName{
    public int PropName{get;set;}
    public ClassName{
        PropName=0;  //Default Value
    }
}
2
4.09.2014 20:44:06

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

2
11.01.2016 11:33:09

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

4
18.07.2016 16:39:49

В 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;
    }
}
45
29.09.2017 16:34:33
У меня еще нет C # 6.0, и я проверял, какая версия мне нужна для значений по умолчанию в авто-свойствах. C # 6.0 также устраняет необходимость иметь { get; set; }или { get; private set; }как иначе установка значения будет заблокирована компилятором?
freefaller 20.04.2018 11:20:56

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

18
30.10.2016 02:16:41

В версии 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; 
 }
30
26.09.2017 05:39:46
Это хорошо, но только второй из трех примеров является авто-свойством.
Aluan Haddad 22.02.2018 08:50:47
Также рассмотрим пример, class C { public DateTime P { get; } = DateTime.Now; public DateTime Q => DateTime.Now; }где оба свойства Pи Qимеют только геттер, но поведение Pи Qочень разные!
Jeppe Stig Nielsen 13.07.2019 15:19:50
private string name;
public string Name 
{
    get 
    {
        if(name == null)
        {
            name = "Default Name";
        }
        return name;
    }
    set
    {
        name = value;
    }
}
3
1.11.2018 14:51:57
Я думаю, что спрашивающий хотел авто-свойство, то есть неабстрактное свойство в классе или структуре, где вы используете только get;точку с запятой (часто в сочетании с set;), чтобы указать, что компилятор должен getавтоматически генерировать тело метода доступа.
Jeppe Stig Nielsen 2.11.2018 08:59:16
Кроме того, этот код имеет побочный эффект возврата к значению по умолчанию, когда явно установлено значение NULL.
MarkO 5.12.2018 12:27:18

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

public sealed  class Employee
{
    public int Id { get; set; } = 101;
}
4
20.08.2019 03:58:23