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

StackOverflow https://stackoverflow.com/questions/40730

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

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

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

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

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

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

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

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 # 6.0 (и выше) для еще более элегантных и лаконичных конструкций, таких как:

public class Person{

    public string FullName  => 
    var p = new Person();

    p.FullName; // First Last

    p.First = "Jon";
    p.Last = "Snow";

    p.FullName; // Jon Snow
quot;{First} {Last}"; // expression body notation public string First { get; set; } = "First"; public string Last { get; set; } = "Last"; }

Вы можете использовать вышеперечисленное следующим образом

<*>

Чтобы можно было использовать вышеуказанное " = > " примечание, свойство должно быть только для чтения, и вы не используете ключевое слово get accessor.

Подробная информация о MSDN

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

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 и выше вы можете просто использовать синтаксис:

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

Обратите внимание, что для свойства readonly просто опустите набор, как показано ниже:

public object Foo { get; } = bar;

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

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

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

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

http://msdn.microsoft.com/en- нас / библиотека / system.componentmodel.defaultvalueattribute.aspx

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

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

public Class ClassName{
    public int PropName{get;set;}
    public ClassName{
        PropName=0;  //Default Value
    }
}
private string name;
public string Name 
{
    get 
    {
        if(name == null)
        {
            name = "Default Name";
        }
        return name;
    }
    set
    {
        name = value;
    }
}

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

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

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

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

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

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

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

public SubClass() : base() { }

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

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

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

    public sealed  class Employee
{
    public int Id { get; set; } = 101;
}
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 givng SomeFlag по умолчанию false.

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

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

        SomeFlag = value;        
    }
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top