автор | |
---|---|
веб -сайт | https://github.com/lsauer/csharp-singleton |
лицензия | MIT Лицензия |
текущий | |
упаковка | PM> Install-Package CSharp.Portable-Singleton |
описание | Общая, портативная, задокументированная и простая в использовании внедрение с шаблоном, для обеспечения соблюдения и управления отдельными экземплярами |
документация | Полная ссылка v2.0.0.4 |
поднятый |
|
Полная версия | Nuget | Строить | Nuget Install |
---|---|---|---|
Csharp.portable-Singleton | PM> Install-Package CSharp.Portable-Singleton |
Социальный:
Пожалуйста, посетите здесь полную ссылку, которая также включена в пакет Nuget.
PM> Install-Package CSharp.Portable-Singleton
.using Core.Singleton;
ПолемMySingleton : Singleton<MySingleton>
.Найдите ниже пример, чтобы дать представление о том, как будет выглядеть код на практике:
using Core . Singleton ;
public class AClass : Singleton < AClass >
{
// a public parameterless constructor is required
public AClass ( ) { }
public AMethod ( ) { Console . Write ( " Write called " ) ; }
}
AClass . CurrentInstance . AMethod ( ) ;
System . Diagnostics . Debug . Assert ( ReferenceEquals ( new AClass ( ) , AClass . CurrentInstance ,
" Same Instance " ) ;
.NET не особенно обеспечивает соблюдение шаблонов проектирования программного обеспечения. Синглтонский шаблон имеет заметное использование в программном обеспечении в качестве модели создания проектирования , в котором может быть создан только один экземпляр объекта, что обычно расширяет полезность синглетонов на создание или обертывание ресурсов с одним доступом.
Создание нового Singleton просто: объявление о наследстве предполагаемого класса Синглтона общим однолетным классом Singleton<>
достаточным.
Такой как:
internal class MyClass : Singleton < MyClass > {
.. .
}
Примером использования для Singletons будет улучшенная консольная обертка для приложений .NET Console, другие типичные сценарии были бы такими, когда производительность и синхронизирующие аспекты будут нести.
ПРИМЕЧАНИЕ. Возможно, крупномасштабные приложения, работающие на современных платформах, могут прибегнуть к улучшению решений по сравнению с синглетами, особенно посредством фронтовой поддержки моделей дизайна.
Для начала рекомендуется придерживаться следующего синтаксиса:
namespace MyNamespace {
using Core . Singleton ;
public class MyClass : Singleton < MyClass > { } ;
var somePropertyValue = Singleton < MyClass > . CurrentInstance . SomeProperty ;
// ...and for a method:
var someMethodValue = Singleton < MyClass > . CurrentInstance . Add ( 1 , 2 ) ;
}
Существует несколько других способов инициализации нового экземпляра Singleton<T>
, в котором T
является типом соответствующего класса логического синглтона, ссылающегося на класс, реализующий пользовательскую логику.
Singleton<T>.CurrentInstance
или Singleton<T>.Instance
впервыеnew T()
SingletonAttribute
, такого как [Singleton]class T : Singleton<T>{...}
и впоследствии вызов Initialize()
из экземпляра Singletonmanager
Activator.CreateInstance(typeof(T));
new T(...)
SingletonManager
(см. Ниже)TypeInfo
ToSingleton()
Eg typeof(MyClass).GetTypeInfo().ToSingleton()
Examples
для кода и сценариев корпуса Общая конструкция Singleton<T>
имеет следующие статические свойства, которые упоминаются в EnumSingletonProperty.cs
:
[ Description ( " The current or created instance of the singleton " ) ]
CurrentInstance = 1 << 1 ,
[ Description ( " The internally created instance of the singleton " ) ]
Instance = 1 << 2 ,
[ Description ( " Gets whether the singleton of type TClass is initialized " ) ]
Initialized = 1 << 3 ,
[ Description ( " Gets whether the singleton of type TClass is disposed " ) ]
Disposed = 1 << 4 ,
[ Description ( " Gets whether the singleton of type TClass is blocked for handling " ) ]
Blocked = 1 << 5 ,
В особых случаях утилизация полезно или даже необходимо. См. Примеры для случаев.
myobj is ISingleton
typeof(MyClass).GetTypeInfo().IsSingleton()
Соответственно, опустите вызов GetTypeInfo()
как показано выше, если тип сравнения уже является экземпляром TypeInfo
.
(Instance == null)
Следующие свойства следуют Конвенции INotifyPropertyChanged
, но не реализуют его, в то же время используя пользовательскую тип SingletonPropertyEventHandler
, а не в Cannonical PropertyChangedEventHandler
.
Сама PropertyChanged
события , которое было объявлено статичным, позволяет слушать Disposed
и Initialized
даже если сам экземпляр Синглтона утилизируется и бесплатно для сбора мусора.
public static event SingletonEventHandler PropertyChanged ;
Кроме того, событие запускается при изменении Manager
недвижимости. Это свойство используется для впрыскивания зависимости сеттера в экземпляре SingletonManager, реализующего ISingletonManager
.
В случае нескольких классов синглтона в данном проекте рекомендуется использовать и разобраться с экземпляром SingletonManager
.
Например, для прослушивания события Disposed
для задач пост-очистки, во время выключения или выхода приложения, можно использовать аналогичную кодовую выборку следующим образом:
Singleton < MyClass > . PropertyChanged += ( sender , arg ) => {
if ( arg . Property == SingletonProperty . Disposed ) {
.. .
}
.. .
} ;
//... prep the application until it is sensible to init the singleton
var logger = Singleton < RenderLogger > . GetInstance ( ) ;
Обратите внимание, что на этом этапе синглтон даже не должен быть инициализирован, что позволяет безопасно интиализовать типичные элементы IStream
в синглтонском конструкторе.
Eventhandler of PropertyChanged
передает экземпляр ISingleton
в качестве первого аргумента, а в качестве второго параметра - экземпляр SingletonPropertyEventArgs
, который содержит следующие свойства:
Name
: строка, содержащая имя измененного свойстваValue
: текущее значение в штучной упаковкеProperty
: собственность, закодированная как значение Enum of SingletonProperty
Следующий выдержка кода создает новый экземпляр SingletonPropertyEventArgs
:
var propertyName = SingletonProperty . Instance . ToString ( ) ;
var propertyValue = 100 ;
var args = new SingletonPropertyEventArgs ( SingletonProperty . Initialized , propertyValue ) ;
В следующем примере демонстрируется динамическое использование GetValue
в рамках EventHandler, чтобы получить доступ к свойствам Singleton, не известными до среды выполнения.
Singelton < MyClass > . PropertyChanged += ( sender , arg ) =>
{
if ( arg . Property == SingletonProperty . Initialized )
{
var value = sender . GetValue ( " Value " ) ;
}
} ;
Как правило, рекомендуется ACCSS Properties аналогичных синглтонов через пользовательские интерфейсы (то есть ISingletonTemplate<TCommonDenominator>
) и выполнять конкретные типичные чеки с использованием оператора is
наряду с явными составами:
Singelton < MyClass > . PropertyChanged += ( sender , arg ) =>
{
if ( arg . Property == SingletonProperty . Initialized )
{
if ( sender is MyClass /*check including inherited types*/ ) {
var senderTyped = sender as MyClass ;
senderTyped . SetDateTime ( DateTime . Now ) ;
} else if ( sender . GetType ( ) == typeof ( MyStrictClass ) /*check excluding inherited types*/ ) {
var senderTyped = sender as MyStrictClass ;
Console . WriteLine ( senderTyped . SayHello ( ) ) ;
} else {
return ;
}
// do something else if the type got matched
}
} ;
В следующем примере класс AClass
реализует «Синглтонскую бизнес -логику» и наследует от Singleton<>
.
Достаточно включить сборки, пространства имен и вывод : Singleton<AClass>
Чтобы получить ожидаемое тестируемое поведение:
using Core . Extensions .
public class AClass : Singleton < AClass >
{
public string AMethod ( [ CallerMemberName ] string caller = " " )
{
return caller ;
}
public static string AStaticMethod ( [ CallerMemberName ] string caller = " " )
{
return caller ;
}
}
static void Main ( string [ ] args )
{
Console . WriteLine ( " Running: " + typeof ( Program ) . Namespace + " . Press any key to quit... " ) ;
var aClass = new AClass ( ) ;
Console . WriteLine ( " Expected: 'Main'; Observed: '{0}' " , aClass . AMethod ( ) ) ;
Console . WriteLine ( " Expected: 'Main'; Observed: '{0}' " , AClass . CurrentInstance . AMethod ( ) ) ;
Console . WriteLine ( " Expected: 'Main'; Observed: '{0}' " , AClass . AStaticMethod ( ) ) ;
object bClass = null ;
try
{
bClass = new AClass ( ) ;
}
catch ( SingletonException exc )
{
if ( exc . Cause == SingletonCause . InstanceExists )
bClass = AClass . CurrentInstance ;
}
var condition = Object . ReferenceEquals ( aClass , bClass ) ;
//> true
var input = Console . ReadKey ( true ) ;
}
Примечание. В папке примеров приведены еще много примеров .
Этот пример выше даст ожидаемый результат:
Running: Examples.Example1. Press any key to quit...
Expected: ' Main ' ; Observed: ' Main '
Expected: ' Main ' ; Observed: ' Main '
Expected: ' Main ' ; Observed: ' Main '
Класс Синглтона может бросить SingletonException
(см. Рис. 1).
Они ссылаются в EnumSingletonCause.cs
.
[ Description ( " Indicates the default or unspecified value " ) ]
Unknown = 1 << 0 ,
[ Description ( " Indicates an existing Singleton instance of the singleton class `T` " ) ]
InstanceExists = 1 << 1 ,
[ Description ( " Indicates that the created Singleton instance does not have a parent class " ) ]
NoInheritance = 1 << 2 ,
[ Description ( " Indicates that an exception by another class or module was caught " ) ]
InternalException = 1 << 3 ,
[ Description ( " Indicates that the Singleton must not be instanced lazily through an Acccessor, but the instance explcitely declared in the source-code " ) ]
NoCreateInternal = 1 << 4 ,
[ Description ( " Indicates that the Singleton must not be disposed " ) ]
NoDispose = 1 << 5 ,
[ Description ( " Indicates an existing mismatch between the singleton class `T` and the logical singleton class or parent-class invoking the constructor " ) ]
InstanceExistsMismatch = 1 << 6 ,
Для глобальной инициализации, а также сужения цели синглтона, логический класс Синглтона всегда должен быть приписан [Singleton]
как показано в следующем примере кода:
[ Singleton ( disposable : false , initByAttribute : false , createInternal : true ) ]
public class AClass : Singleton < AClas > {
.. .
}
Атрибут имеет три доступных свойства:
Disposable
(default = false): установите на true
, если разрешено утилизироватьCreateInternal
(default = true): установите на false
, если Singleton должен быть создан извне только путем явного объявления в коде пользовательского исходного кодаInitByAttribute
(default = true): установить в true
, чтобы разрешить совместную инициализацию методом SingletonManager
Initialize
Чтобы управлять несколькими типами и экземплярами Singleton в большом приложении, используйте класс SingletonManager
следующим образом:
Следующий пример повторяется над Pool
синглтонов и выполняет логику, зависящую от типа Синглтона:
var singletonTypes = new List<Type>() { typeof(ParentOfParentOfAClass), typeof(ParentOfAClass), typeof(IndispensibleClass) };
// create the singletons and add them to the manager
var singletonManager = new SingletonManager(singletonTypes);
foreach (var singleton in singletonManager.Pool)
{
if (singleton.Value is ParentOfParentOfAClass)
{
var instanceTyped = singleton.Value as ParentOfParentOfAClass;
Console.WriteLine($"POPOAClass ImplementsLogic: {instanceTyped.ImplementsLogic}");
} else {
Console.WriteLine(singleton.Value.GetType().FullName);
}
}
Свойство singletonManager.Pool
предоставляет доступ к безопасному потоку, ConcurrentDictionary<Type, ISingleton>
экземпляр, который позволяет записывать запросы в знакомых синтаксисе LINQ.
Утилизированные синглтоны никогда не удаляются, но настроены на null
, используя метод AddOrUpdate
SingletonManager.
Для создания новых экземпляров известного типа используйте общий метод CreateInstance следующим образом:
var singletonManager = new SingletonManager ( ) ;
var gameStatics = singletonManager . CreateSingleton < GameStatics > ( ) ;
Если тип известен только во время выполнения или доступен динамически передавать тип как аргумент, как показано в следующем примере кода:
var singletonManager = new SingletonManager ( ) ;
var getInstance = ( type ) => {
var gameStatics = singletonManager . CreateSingleton ( type ) ;
} ;
getInstance ( typeof ( GameStatics ) ) ;
В самом классе Синглтона нет ничего, что не могло бы предотвратить реализацию сериализатора, однако реализация, а также тестирование находится в руках разработчика.
Общие решения не рекомендуются, а скорее конкретные протестированные реализации этих синглетов, где это необходимо. Например, в сценарии состояния Hibernate / Resume. Для этой цели рекомендуется использовать Singletonmanager.
Также взгляните на эту дискуссию
Эта библиотека была протестирована в рамках тестирования XUNIT. Тесты проводятся с несколькими классами, один из AClass
, придерживающийся простой схемы пуннонического наследования:
Рис. 1:
Если вы уверены, что столкнулись с ошибкой, пожалуйста, выдвигайте здесь новую проблему.
В сценарии вложенного наследования нескольких классов, унаследовавших друг друга иерархически, и определенный базовый класс, полученный из Синглтона, важно определить логический класс Синглтона. Это тот класс, предназначенный для реализации логики монета после единой ответственности.
Это также класс, который определяет общий тип T
из которого базовый класс - класс, за исключением самого Singleton<T>
, должен наследовать Singleton<T>
Для более сложного сценария в одиночку наследство, пожалуйста, см. README_Example_Advanced.md
Для поддержания хорошей читаемости при использовании этой библиотеки:
singleton<T>
: например, ParentOfParentOfAClass.Instance
в порядке, но избегайте AClass.Instance
SingletonAttribute