Является ли реализация одиночного с использованием авто-свойства хорошей идеей?
Недавно я узнал об авто-свойствах, и они мне очень понравились. В данный момент я пытаюсь использовать их везде, где могу. Не для того, чтобы просто использовать их везде, а для того, чтобы увидеть, насколько хорошо они работают в большинстве ситуаций.
Сейчас я делаю синглтон и думал:"Эй, давай попробуем здесь и авто-свойства".
public class MySingleton
{
public static MySingleton MySingleton { get; private set; }
private MySingleton() {}
static MySingleton() { MySingleton = new MySingleton(); }
}
Итак, мой вопрос:"Это хорошая идея для реализации подобного синглтона?"
Я не спрашиваю, является ли синглтон вообще хорошей идеей.
6 ответов
Я бы лично этого не делал. Мне не нравится использовать автоматически реализуемые свойства с частным установщиком, который вы никогда не вызываете, где на самом деле вы хотите, чтобы свойство только для чтения поддерживалось переменной только для чтения. Это всего лишь еще одна строка кода, чтобы быть более ясным о том, что вы имеете в виду:
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() {}
}
Я бы подошел к этому немного в другом направлении, чем Джон. Независимо от того, является ли объект одноэлементным, логически лучше всего его моделировать как свойство?
Свойства должны представлять... свойства. (Капитан Очевидный снова наносит удар!) Вы знаете. Цвет. Длина. Рост. Название. Родитель. Все вещи, которые вы логически считаете собственностью вещи.
Я не могу представить себе свойство объекта, который логически является единичным. Может быть, вы придумали сценарий, о котором я не подумал; У меня еще не было диетического доктора Пеппера сегодня утром. Но я подозреваю, что это злоупотребление семантикой модели.
Можете ли вы описать, что такое синглтон, и почему вы считаете, что это свойство чего-то?
Все сказанное, я сам часто использую этот шаблон; обычно так:
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();
просто кажется странным
То, что в этом случае лучше иметь поле только для чтения и регулярное свойство, или статический ctor и autoprop, кажется менее интересным, чем вопрос о том, стоит ли вообще делать его свойством. В "пуристском" настроении я, скорее всего, примкну к Джону и сделаю это поле только для чтения. Но я также часто использую паттерн создания autoprops с частными установщиками для логически неизменных объектов, просто из-за лени.
Как это для того, чтобы принять все стороны вопроса?
Посмотрите, как правильно реализовать синглтон.
И ты понимаешь, что одиночки - это зло, верно?
Я не вижу причин, почему это не будет правильно. В конце концов, авто-свойства являются просто синтаксическим сахаром для методов доступа к частному (генерируемому компилятором) вспомогательному полю.
Авто собственность? Нет, я бы не стал использовать сеттер на синглтоне, да, я сделал. Я думаю, что вы хотите больше контроля над этим, чем автоматическое свойство даст вам.
... конструктивные отзывы приветствуются, пожалуйста. Это похоже на смелый (или глупый) шаг в этой уважаемой компании...
Мой сценарий - приложение WPF с текущим проектом, который можно загрузить и сохранить. Текущие настройки проекта используются во всем приложении...
- в привязках WPF в пользовательском интерфейсе, чтобы пользователь мог изменить настройки, следовательно,
INotifyPropertyChanged
интерфейс. - Я также использую https://github.com/Fody/PropertyChanged, но это не делает статических изменений свойств, следовательно
NotifyStaticPropertyChanged
, INotifyPropertyChanged
отлично работает с привязками WPF к свойствам синглтона.- Экземпляр
Settings
[de] сериализуется с использованием JSON.NET, следовательно,[JsonIgnore]
атрибут на синглтоне. Я проверяю его перед загрузкой в синглтон или сохранением на диск. - регистратор Serilog. Вы регистрируете вещи, верно?
- синглтон
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; }
}
использование для установки синглтона во вновь загруженный проект, settings
это просто
Settings settings = new Settings();
// load, save, deserialize, set properties, go nuts
Settings.CurrentSettings = settings;
Сеттер, вероятно, не является потокобезопасным, но я установил его только в одном месте из потока пользовательского интерфейса, поэтому я не боюсь. Вы можете сделать его безопасным, следуя уважаемому совету на http://csharpindepth.com/Articles/General/Singleton.aspx
Я понимаю, что OP не спрашивал о WPF, но я думаю, что важно показать, почему вы можете установить синглтон. Я сделал это, потому что это самое простое решение.
Заключение + альтернативный синтаксис с лямбда-стилем (>= 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 для C#