Как вы даете C-Auto-Property значение по умолчанию? - PullRequest
1663 голосов
/ 03 сентября 2008

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

Использование конструктора:

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

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

Ответы [ 23 ]

10 голосов
/ 18 января 2013

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

[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
9 голосов
/ 04 сентября 2008

В 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

5 голосов
/ 18 июля 2016

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

3 голосов
/ 03 сентября 2008

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

3 голосов
/ 05 сентября 2014
public Class ClassName{
    public int PropName{get;set;}
    public ClassName{
        PropName=0;  //Default Value
    }
}
3 голосов
/ 01 ноября 2018
private string name;
public string Name 
{
    get 
    {
        if(name == null)
        {
            name = "Default Name";
        }
        return name;
    }
    set
    {
        name = value;
    }
}
2 голосов
/ 11 января 2016

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

2 голосов
/ 03 сентября 2008

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

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

2 голосов
/ 31 июля 2012

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

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

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

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

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

public SubClass() : base() { }

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

2 голосов
/ 18 февраля 2019

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

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