Является ли реализация одиночного с использованием auto-свойства хорошей идеей? - PullRequest
10 голосов
/ 22 января 2010

Я недавно узнал об авто-свойствах, и они мне очень нравятся. В данный момент я пытаюсь использовать их везде, где могу. Не для того, чтобы просто использовать их везде, а для того, чтобы увидеть, насколько хорошо они работают в большинстве ситуаций.

Сейчас я делаю синглтон и думаю: «Эй, давайте попробуем и авто-свойства здесь».

public class MySingleton
{
    public static MySingleton MySingleton { get; private set; }

    private MySingleton() {}

    static MySingleton() { MySingleton = new MySingleton(); }
}

Итак, мой вопрос: «Это хорошая идея для реализации подобного синглтона?»

Я не спрашиваю, является ли синглтон вообще хорошей идеей.

Ответы [ 6 ]

16 голосов
/ 22 января 2010

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

public sealed class MySingleton
{
    private static readonly MySingleton mySingleton;
    public static MySingleton MySingleton { get { return mySingleton; } }

    private MySingleton() {}

    static MySingleton() { mySingleton = new MySingleton(); }
}

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

Другими словами:

  • Да, это будет работать.
  • Нет, я не думаю, что это хорошая идея.

Начиная с C # 6, это проще с автоматически реализуемыми свойствами только для чтения:

public sealed class MySingleton
{
    public static MySingleton MySingleton { get; } = new MySingleton();    
    private MySingleton() {}         
    static MySingleton() {}
}
10 голосов
/ 22 января 2010

Я бы подошел к этому немного в другом направлении, чем Джон. Независимо от того, является ли объект одноэлементным, логически лучше всего его моделировать как свойство в первую очередь? Свойства должны представлять ... свойства. (Капитан Очевидный снова наносит удар!) Вы знаете. Цвет. Длина. Рост. Название. Родитель. Все вещи, которые вы бы логически считали собственностью вещи.

Я не могу представить свойство объекта, который логически является singleton . Может быть, вы придумали сценарий, о котором я не подумал; У меня еще не было диеты, доктор Пеппер сегодня утром. Но я подозреваю, что это злоупотребление семантикой модели.

Можете ли вы описать, что такое синглтон, и почему вы считаете, что он является собственностью чего-то?

Все, что сказано, я сам часто использую эту модель; обычно так:

class ImmutableStack<T>
{
    private static readonly ImmutableStack<T> emptystack = whatever;
    public static ImmutableStack<T> Empty { get { return emptystack; } }
    ...

Является ли "Empty" логически свойством неизменного стека? Нет. Здесь убедительная выгода от умения сказать

var stack = ImmutableStack<int>.Empty;

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

var stack = ImmutableStack<int>.GetEmpty();

просто кажется странным.

Лучше ли в этом случае иметь поле только для чтения и регулярное свойство, или статический ctor и autoprop, кажется менее интересным, чем вопрос, делать ли это свойством вообще. В «пуристском» настроении я, скорее всего, примкну к Джону и сделаю это поле только для чтения. Но я также часто использую шаблон создания autoprops с частными установщиками для логически неизменных объектов, просто из-за лени.

Как это для того, чтобы принять все стороны вопроса?

1 голос
/ 22 января 2010

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

0 голосов
/ 12 сентября 2018

Заключение + альтернативный синтаксис с лямбда-стилем (> = C # 6), он же вычисляемое свойство (он же член в выражении):

Код функционально полностью эквивалентен ответу Джона Скита, и здесь снова «Экземпляр». Я не ожидаю похвалы за это, но я думаю, что эта обновленная сводка с объяснением в одном месте того стоит, потому что этот вопрос и ответы по C # 6 расширяют старую закрытую ветку, где обсуждались варианты Singleton.

Можно утверждать, что стиль автоматического свойства с явно отсутствующим набором выражает более ясное намерение свойства только для чтения, но, в конце концов, оно основано на стиле, и оба стиля распространены в современном C #.

public sealed class MySingleton
{
    public static MySingleton Instance => new MySingleton(); // Assure that instantiation is only done once (because of static property) and in threadsafe way, and as this is an alternative style for a readonly-property, there is no setter
    private MySingleton() {} // Assure, that instantiation cannot be done from outside the class        
    static MySingleton() {} // Assure partly lazyness, see below     
}

Вот все подробности и историческая справка в одном месте:

Дискуссия о ленивости: http://csharpindepth.com/Articles/General/Beforefieldinit.aspx
Упрощенная сводка: вышеприведенная реализация ведет себя лениво, пока в классе не введены другие статические поля / свойства. (Но это область, которая может зависеть от реализации .NET.)

Обсуждение различных реализаций Singleton и безопасности потоков (старые стили C #): http://csharpindepth.com/Articles/General/Singleton.aspx

Оригинальная тема (закрытая): Singleton Pattern для C #

0 голосов
/ 21 июля 2017

Авто собственность? Нет, я бы не стал использовать сеттер на синглтоне, да, я сделал. Я думаю, вы хотите иметь больше контроля над ним, чем даст вам свойство auto.

... конструктивные отзывы приветствуются, пожалуйста. Это похоже на смелый (или глупый) шаг в этой уважаемой компании ...

Мой сценарий, приложение WPF, в котором есть текущий проект, который можно загрузить и сохранить. Текущие настройки проекта используются во всем приложении ...

  • в привязках WPF в пользовательском интерфейсе, чтобы пользователь мог изменять настройки, следовательно, интерфейс INotifyPropertyChanged.
  • Я также использую Fody.PropertyChanged , но это не приводит к статическим изменениям свойств, поэтому NotifyStaticPropertyChanged.
  • INotifyPropertyChanged отлично работает с привязками WPF к свойствам синглтона.
  • Экземпляр Settings сериализуется [de] с использованием JSON.NET, следовательно, атрибут [JsonIgnore] в синглтоне. Я проверяю его перед загрузкой в ​​синглтон или сохранением на диск.
  • регистратор Serilog . Вы регистрируете вещи, верно?
  • синглтон public с геттером public, поскольку привязки WPF работают только с открытыми свойствами. Установщик internal не влияет на это. Все свойства Settings являются общедоступными для привязки WPF.

Я оставил весь «шум» в коде, потому что некоторые могут найти его полезным.

class Settings : INotifyPropertyChanged
{
    private static Settings _currentSettings = new Settings();

    /// <summary> The one and only Current Settings that is the current Project. </summary>
    [JsonIgnore] // so it isn't serialized by JSON.NET
    public static Settings CurrentSettings //  http://csharpindepth.com/Articles/General/Singleton.aspx 
    {
        get { return _currentSettings; }

        // setter is to load new settings into the current settings (using JSON.NET). Hey, it works. Probably not thread-safe.
        internal set 
        {
            Log.Verbose("CurrentSettings was reset. Project Name: {projectName}", value.ProjectName);
            _currentSettings = value;
            _currentSettings.IsChanged = false;
            NotifyStaticPropertyChanged("CurrentSettings");
        }
    }

    // http://10rem.net/blog/2011/11/29/wpf-45-binding-and-change-notification-for-static-properties
    /// <summary> Fires when the Curent CurrentTvCadSettings is loaded with new settings
    ///           Event queue for all listeners interested in StaticPropertyChanged events. </summary>
    public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged = delegate { };
    private static void NotifyStaticPropertyChanged(string propertyName)
    {
        StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
    }

    // various instance properties including ....

    public string ProjectName {get; set;}

    [JsonIgnore]
    public bool IsChanged { get; set; } 
}

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

Settings settings = new Settings();
// load, save, deserialize, set properties, go nuts
Settings.CurrentSettings = settings;

Установщик, вероятно, не является потокобезопасным, но я установил его только в одном месте из потока пользовательского интерфейса, поэтому я не боюсь. Вы можете сделать его безопасным, следуя уважаемому совету на http://csharpindepth.com/Articles/General/Singleton.aspx

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

0 голосов
/ 22 января 2010

Конечно, я не вижу никаких проблем с этим.

...