| Autor | |
|---|---|
| Webseite | https://github.com/lsauer/csharp-singleton |
| Lizenz | MIT -Lizenz |
| aktuell | |
| Paket | PM> Install-Package CSharp.Portable-Singleton |
| Beschreibung | Eine generische, tragbare, dokumentierte und einfach zu verwendende Singleton -Muster -Implementierung, um einzelne Instanzen durchzusetzen und zu verwalten |
| Dokumentation | Vollständige Referenz v2.0.0.4 |
| gesetzt |
|
| Vollversion | Nuget | Bauen | Nuget Install |
|---|---|---|---|
| CSHARP.Portable-Singleton | PM> Install-Package CSharp.Portable-Singleton |
Sozial:
Bitte besuchen Sie hier eine vollständige Referenz, die auch im Nuget -Paket enthalten ist.
PM> Install-Package CSharp.Portable-Singleton .using Core.Singleton; .MySingleton : Singleton<MySingleton> .Suchen Sie unten ein Beispiel, um einen Blick darauf zu geben, wie der Code in der Praxis aussehen wird:
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 erzwingt nicht besonders Software -Designmuster. The singleton pattern is of notable use in software as a creational design pattern , wherein only one instance of an object may be instantiated, thus generally extending the usefulness of singletons to the creation or wrapping of single-access resources.
Creating a new singleton is straightforward: Declaring an inheritance of the intended singleton class to the generic singleton class Singleton<> suffices.
Wie zum Beispiel:
internal class MyClass : Singleton < MyClass > {
.. .
}Ein Nutzungsbeispiel für Singletons wäre eine verbesserte Konsolenverpackung für .NET -Konsolenanwendungen. Andere typische Szenarien wären so, wo Leistung und Synchronisierungsaspekte zur Bärung gebracht werden.
Note: Arguably large scale applications running on modern platforms can resort to improved solutions over singletons particularly through framework support of design patterns.
Um loszulegen, wird empfohlen, sich an die folgende Syntax zu halten:
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 ) ;
} There are several other ways to initialize a new Singleton<T> instance, wherein T is the type of the respective logical singleton class, refering to the class implementing the custom logic.
Singleton<T>.CurrentInstance or Singleton<T>.Instance for the first timenew T()SingletonAttribute such as [Singleton]class T : Singleton<T>{...} and subsequently calling Initialize() from a Singletonmanager instanceActivator.CreateInstance(typeof(T));new T(...)SingletonManager (see below)TypeInfo Extension Method ToSingleton() eg typeof(MyClass).GetTypeInfo().ToSingleton()Examples for code and case scenarios The generic Singleton<T> construct has the following static properties, which are referenced in 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 ,In besonderen Fällen ist die Entsorgung hilfreich oder sogar notwendig. See the Examples for cases.
myobj is ISingletontypeof(MyClass).GetTypeInfo().IsSingleton() Respectively, omit the call to GetTypeInfo() as shown above, if the comparison type is already a TypeInfo instance.
(Instance == null) The following properties follow the convention of INotifyPropertyChanged but do not implement it, whilst using a custom typed SingletonPropertyEventHandler instead of the cannonical PropertyChangedEventHandler .
The event PropertyChanged itself is declared static to allow listening to Disposed and Initialized even when the singleton instance itself is disposed and free for garbage collection.
public static event SingletonEventHandler PropertyChanged ; Additionally, an event is triggered when the property Manager changes. This property is used for setter dependency injection of a SingletonManager instance implementing ISingletonManager .
In case of several singleton classes in a given project, it is recommended to use and pass around a SingletonManager instance.
For instance to listen to the Disposed event for post-cleanup tasks, during the shutdown or exiting of an application, one may use a similar code-sample as follows:
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 ( ) ; Note, that the singleton does not even have to be initialized at this point, making it safe to intialize typical IStream elements within the singleton constructor.
The EventHandler of PropertyChanged passes an instance of ISingleton as the first argument, and as second parameter an instance of SingletonPropertyEventArgs , which contains the following properties:
Name : a string containing the name of the changed propertyValue : the boxed current value of the propertyProperty : the property encoded as an enum value of SingletonProperty The following code excerpt creates a new SingletonPropertyEventArgs instance:
var propertyName = SingletonProperty . Instance . ToString ( ) ;
var propertyValue = 100 ;
var args = new SingletonPropertyEventArgs ( SingletonProperty . Initialized , propertyValue ) ; The following example demonstrates the dynamic use of GetValue within an EventHandler, to access singleton properties not known until runtime.
Singelton < MyClass > . PropertyChanged += ( sender , arg ) =>
{
if ( arg . Property == SingletonProperty . Initialized )
{
var value = sender . GetValue ( " Value " ) ;
}
} ; Generally, it is recommended to accss properties of similar singletons through custom interfaces (ie ISingletonTemplate<TCommonDenominator> ) and perform specific typechecks using the is operator alongside explicit casts:
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
}
} ; In the following example the class AClass implements the 'singleton business logic', and inherits from Singleton<> .
It suffices to include the assemblies, namespaces and derivation : Singleton<AClass> to get the expected, tested behavior:
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 ) ;
}Note: Many more examples are provided in full, within the examples folder.
Dieses obige Beispiel liefert das erwartete Ergebnis von:
Running: Examples.Example1. Press any key to quit...
Expected: ' Main ' ; Observed: ' Main '
Expected: ' Main ' ; Observed: ' Main '
Expected: ' Main ' ; Observed: ' Main ' A Singleton class can throw a SingletonException (See Fig 1).
These are referenced in 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 , For global initialization as well as constriction the purpose of a singleton, the logical Singleton class should always be attributed with [Singleton] as shown in the following code example:
[ Singleton ( disposable : false , initByAttribute : false , createInternal : true ) ]
public class AClass : Singleton < AClas > {
.. .
}Das Attribut enthält drei zugängliche Eigenschaften:
Disposable (default=false): Set to true if the is allowed to be disposedCreateInternal (default=true): Set to false if the Singleton is only supposed to be instantiated externally by explicit declaration within the user source-codeInitByAttribute (default=true): Set to true to allow joint initialization by the SingletonManager method Initialize To manage several singleton types and instances throughout a large application, use the SingletonManager class as follows:
The following example iterates over a Pool of Singletons and performs logic dependent on the type of singleton:
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);
}
}
The singletonManager.Pool property provides access to a thread-safe, ConcurrentDictionary<Type, ISingleton> instance which allows for writing queries in familiar LINQ Syntax.
Disposed Singletons are never deleted but are set to null using the SingletonManager's AddOrUpdate method.
Um neue Instanzen eines bekannten Typs zu erstellen, verwenden Sie die generische Erstellung wie folgt:
var singletonManager = new SingletonManager ( ) ;
var gameStatics = singletonManager . CreateSingleton < GameStatics > ( ) ;Wenn der Typ nur zur Laufzeit bekannt ist oder den Typ dynamisch als Argument übergeben wird, wie im folgenden Code -Beispiel gezeigt:
var singletonManager = new SingletonManager ( ) ;
var getInstance = ( type ) => {
var gameStatics = singletonManager . CreateSingleton ( type ) ;
} ;
getInstance ( typeof ( GameStatics ) ) ;Es gibt nichts in der Singleton -Klasse selbst, das die Implementierung eines Serialisierers verhindern würde, aber die Implementierung und Tests liegt in den Händen des Entwicklers.
Generische Lösungen werden nicht empfohlen, sondern bei Bedarf spezifische, getestete Implementierungen dieser Singletons. Zum Beispiel in einem Szenario zum Hibernate / Lebenslauf. Es wird empfohlen, den SingletonManager für diesen Zweck zu verwenden.
Schauen Sie sich diese Diskussion auch an
Diese Bibliothek wurde vom Xunit -Test -Framework getestet. Tests are run with several classes, one of with AClass adhering to a straightforward cannonical inheritance schema:
Abb. 1:
Wenn Sie sicher sein, dass Sie einen Fehler gestoßen haben, geben Sie bitte ein neues Problem hier.
In einem verschachtelten Erbszenario mehrerer Klassen, die hierarchisch hierarchisch erben, und eine entschlossene Basisklasse, die von Singleton stammt, ist es wichtig, die logische Singleton -Klasse zu definieren. Dies ist die Klasse, die die Logik des Singleotn nach der einzelnen Verantwortung implementieren soll.
It it also the class that determines the generic type T from which the base class - the class short of Singleton<T> itself, must inherit Singleton<T>
For a more complex inheritance singleton scenario, please refer to README_Example_Advanced.md
Um eine gute Lesbarkeit bei der Verwendung dieser Bibliothek beizubehalten:
singleton<T> : eg ParentOfParentOfAClass.Instance is OK, but avoid AClass.InstanceSingletonAttribute