| автор | |
|---|---|
| веб -сайт | 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() из экземпляра SingletonmanagerActivator.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 ISingletontypeof(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.InstanceSingletonAttribute