C# Автоматическое Свойство - Является этой лучшей практикой 'шаблона'?

Золотой стандарт для программирования речью VoiceCode. Если я помню правильно, они поддерживают C++ и Python.

10
задан Phill Duffy 24 November 2009 в 12:04
поделиться

9 ответов

Это техника, которую я сам очень часто использую. Это также может помочь сэкономить ресурсы памяти, поскольку он не создает экземпляр объекта List <>, если свойство objects фактически не используется в коде-потребителе. Здесь используется техника «ленивой загрузки».

Кроме того, перечисленная вами техника «ленивой загрузки» не является потокобезопасной. Если произойдет несколько одновременных вызовов свойства, вы можете получить несколько вызовов, устанавливающих свойство на новый объект List <>, последовательно перезаписывая любые существующие значения List новым пустым объектом List <>. Чтобы сделать средство доступа Get Thread Safe, вам необходимо использовать оператор Lock , например так:

private IList<BCSFilter> _BCSFilters;

// Create out "key" to use for locking
private object _BCSFiltersLOCK = new Object();

/// <summary>
/// Gets or sets the BCS filters.
/// </summary>
/// <value>The BCS filters.</value>
public IList<BCSFilter> BCSFilters
{
    get
    {
        if (_BCSFilters == null)
        {
            // Lock the object before modifying it, so other
            // simultaneous calls don't step on each other
            lock(_BCSFiltersLOCK)
            {
                if (_BCSFilters == null)
                }
                    _BCSFilters = new List<BCSFilter>();
                }
            }
        }

        return _BCSFilters;
    }
    set
    {
        _BCSFilters = value;
    }
}

Однако, если вам всегда будет нужен экземпляр объекта List <>, немного проще просто создать его внутри конструктор объекта и используйте вместо него автоматическое свойство. Примерно так:

public class MyObject
{
    public MyObject()
    {
        BCSFilters = new List<BCSFilter>();
    }

    public IList<BCSFilter> BCSFilters { get; set; }
}

Дополнительно, если вы оставите "набор" accessor public, тогда код потребления сможет установить для свойства значение Null, что может нарушить работу другого кода потребления. Таким образом, хороший способ не дать потребляющему коду установить значение свойства равным Null - это установить приватный метод доступа. Примерно так:

public IList<BCSFilter> BCSFilters { get; private set; }

Связанный метод состоит в том, чтобы вместо этого вернуть объект IEnumerable <> из свойства. Это позволит вам в любое время заменить тип List <> внутри объекта, и это не повлияет на код потребления. Чтобы вернуть IEnumerable <>, вы можете просто вернуть простой объект List <> напрямую, поскольку он реализует интерфейс IEnumerable <>. Примерно так:

public class MyObject
{
    public MyObject()
    {
        BCSFilters = new List<BCSFilter>();
    }

    public IEnumerable<BCSFilter> BCSFilters { get; set; }
}
32
ответ дан 3 December 2019 в 13:16
поделиться

Это правильный шаблон, если вы хотите:

  • Разрешить внешнему коду заменять весь список (instance.BCSFilters = null)
  • Список волшебным образом создается при чтении . Это сложно, хотя как есть, поскольку вы позволяете пользователю устанавливать для него значение null (в наборе), но не позволяете ему оставаться равным нулю (поскольку более позднее получение приведет к пустому списку).

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

Обычно у меня есть только геттер для моих членов IList, и я могу даже открыть IEnumerable или вернуть копию в get (но вам нужно будет предоставить определенные методы добавления и удаления, поэтому YMMV)

5
ответ дан 3 December 2019 в 13:16
поделиться

К вашему сведению, несколько более лаконичный способ сделать то же самое, что вы уже делаете, может выглядеть так:

private IList<BCSFilter> _BCSFilters;

public IList<BCSFilter> BCSFilters
{
    get
    {
        return _BCSFilters ?? (_BCSFilters = new List<BCSFilter>());
    }
    set
    {
        _BCSFilters = value;
    }
}
5
ответ дан 3 December 2019 в 13:16
поделиться

Ваш подход - это ленивая версия инициализации

public class xyz
{
    public xyz()
    {
        BCSFilters = new List<BCSFilter>();
    }

    public IList<BCSFilter> BCSFilters { get; set; }
}
3
ответ дан 3 December 2019 в 13:16
поделиться

Это пример шаблона отложенной загрузки . Это общепринятый и вполне допустимый шаблон.

Вы можете использовать автоматические свойства в C # и назначить экземпляр свойству в конструкторе. Преимущество шаблона Lazy Load заключается в том, что вы не инициализируете свойство, пока оно не будет вызвано. Это может быть полезно в ситуациях, когда инициализация стоит дорого.

Я предпочитаю автоматические свойства с инициализацией конструктора, потому что синтаксис более лаконичен и требует меньше ввода , если инициализация не является дорогостоящей, в этом случае Lazy Load работает хорошо.

2
ответ дан 3 December 2019 в 13:16
поделиться

Да, это совершенно нормально; -)

Такое ленивое создание не редкость и имеет смысл. Единственное предостережение - вам нужно быть осторожным, если вы вообще ссылаетесь на поле.

Изменить: Но мне придется пойти с Крисом и другими: это (намного) лучший шаблон для использования свойства auto и инициализировать коллекцию в конструкторе.

0
ответ дан 3 December 2019 в 13:16
поделиться

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

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

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

Не проблема в однопоточная среда, но определенно кое-что, о чем следует знать.

10
ответ дан 3 December 2019 в 13:16
поделиться

Это нормальный шаблон. Автосвойства - это просто сокращение для очень простого и, пожалуй, наиболее распространенного сценария со свойствами, а для некоторых сценариев его просто нецелесообразно использовать. Что вы могли бы сделать, так это вместо этого создать экземпляр BCSFilters в конструкторе. Таким образом, вы можете использовать автосвойства, и вам все равно не придется беспокоиться об исключениях с нулевой ссылкой.

0
ответ дан 3 December 2019 в 13:16
поделиться

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

0
ответ дан 3 December 2019 в 13:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: