Является ли реализация синглтона с использованием авто-собственности хорошей идеей?

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

Теперь я делаю синглтон и думал: "Эй, попробуй также авто-свойства здесь".

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

    private MySingleton() {}

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

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

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

Ответ 1

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

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

    private MySingleton() {}

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

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

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

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

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

public sealed class MySingleton
{
    public static MySingleton MySingleton { get; } = new MySingleton();    
    private MySingleton() {}         
    static MySingleton() {}
}

Ответ 2

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

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

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

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

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

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

Является ли "пустой" логически свойство неизменяемого стека? Нет. Здесь неотразимое преимущество:

var stack = ImmutableStack<int>.Empty;

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

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

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

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

Как это для принятия всех сторон вопроса?

Ответ 3

См. это о том, как правильно реализовать синглтон.

И вы знаете, что синглтоны - это зло, верно?

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

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

  • в привязках WPF в пользовательском интерфейсе, чтобы пользователь мог изменить настройки, следовательно, интерфейс INotifyPropertyChanged.
  • Я также использую Fody.PropertyChanged, но это не изменяет статические свойства, следовательно NotifyStaticPropertyChanged.
  • INotifyPropertyChanged отлично работает с привязками WPF к свойствам singleton.
  • Экземпляр Settings является [de] сериализован с использованием JSON.NET, поэтому атрибут [JsonIgnore] на одноэлементном. Я проверяю его перед загрузкой в ​​одноэлементный режим или сохранением его на диске.
  • регистратор Serilog. Вы регистрируете материал, не так ли?
  • singleton имеет public с public getter, потому что привязки 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; } 
}

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

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

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

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