pengarang | |
---|---|
situs web | https://github.com/lsauer/csharp-singleton |
lisensi | Lisensi MIT |
saat ini | |
kemasan | PM> Install-Package CSharp.Portable-Singleton |
keterangan | Generik, portabel, didokumentasikan, dan mudah digunakan implementasi pola singleton, untuk menegakkan dan mengelola instance tunggal |
dokumentasi | Referensi lengkap v2.0.0.4 |
disediakan |
|
Versi Lengkap | Nuget | Membangun | Instal Nuget |
---|---|---|---|
Csharp.portable-singleton | PM> Install-Package CSharp.Portable-Singleton |
Sosial:
Silakan kunjungi di sini untuk referensi lengkap, yang juga termasuk dalam paket Nuget.
PM> Install-Package CSharp.Portable-Singleton
.using Core.Singleton;
.MySingleton : Singleton<MySingleton>
.Temukan contoh di bawah ini untuk memberikan sekilas seperti apa kode itu dalam praktiknya:
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 tidak terlalu menegakkan pola desain perangkat lunak. Pola singleton adalah penggunaan penting dalam perangkat lunak sebagai pola desain kreasi , di mana hanya satu contoh suatu objek yang dapat dipakai, sehingga umumnya memperluas kegunaan singleton ke pembuatan atau pembungkus sumber daya akses tunggal.
Membuat singleton baru langsung: menyatakan warisan kelas singleton yang dimaksudkan untuk kelas Singleton<>
cukup.
Seperti:
internal class MyClass : Singleton < MyClass > {
.. .
}
Contoh penggunaan untuk singleton akan menjadi pembungkus konsol yang lebih baik untuk aplikasi konsol .NET, skenario khas lainnya adalah di mana aspek kinerja dan sinkronisasi dibawa untuk ditanggung.
Catatan: Aplikasi skala besar yang bisa dibilang yang berjalan di platform modern dapat menggunakan solusi yang lebih baik daripada singleton terutama melalui dukungan kerangka kerja dari pola desain.
Untuk memulai, disarankan untuk mematuhi sintaks berikut:
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 ) ;
}
Ada beberapa cara lain untuk menginisialisasi instance Singleton<T>
baru, di mana adalah T
kelas Logical Singleton masing -masing, mengacu pada kelas yang mengimplementasikan logika khusus.
Singleton<T>.CurrentInstance
atau Singleton<T>.Instance
untuk pertama kalinyanew T()
SingletonAttribute
seperti [Singleton]class T : Singleton<T>{...}
dan selanjutnya memanggil Initialize()
dari instance Singletonmanager
Activator.CreateInstance(typeof(T));
new T(...)
SingletonManager
(lihat di bawah)TypeInfo
ToSingleton()
misalnya typeof(MyClass).GetTypeInfo().ToSingleton()
Examples
untuk skenario kode dan kasus Konstruk Singleton<T>
generik memiliki sifat statis berikut, yang dirujuk dalam 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 ,
Dalam kasus khusus pembuangan sangat membantu atau bahkan perlu. Lihat contoh untuk kasus.
myobj is ISingleton
typeof(MyClass).GetTypeInfo().IsSingleton()
Masing -masing, hilangkan panggilan ke GetTypeInfo()
seperti yang ditunjukkan di atas, jika jenis perbandingan sudah menjadi instance TypeInfo
.
(Instance == null)
Properti berikut mengikuti Konvensi INotifyPropertyChanged
tetapi tidak mengimplementasikannya, sementara menggunakan SingletonPropertyEventHandler
yang diketik khusus alih -alih PropertyChangedEventHandler
kanonik yang berpura -pura.
Acara PropertyChanged
sendiri dinyatakan statis untuk memungkinkan mendengarkan untuk Disposed
dan Initialized
bahkan ketika instance singleton itu sendiri dibuang dan gratis untuk pengumpulan sampah.
public static event SingletonEventHandler PropertyChanged ;
Selain itu, suatu acara dipicu ketika Manager
properti berubah. Properti ini digunakan untuk injeksi ketergantungan setter dari instance SingletonManager yang mengimplementasikan ISingletonManager
.
Dalam kasus beberapa kelas singleton dalam proyek tertentu, disarankan untuk menggunakan dan melewati contoh SingletonManager
.
Misalnya untuk mendengarkan acara Disposed
untuk tugas-tugas pasca-pembersihan, selama shutdown atau keluar dari aplikasi, orang dapat menggunakan sampel kode yang sama sebagai berikut:
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 ( ) ;
Perhatikan, bahwa singleton bahkan tidak harus diinisialisasi pada titik ini, membuatnya aman untuk mengintalionisasi elemen -elemen IStream
khas dalam konstruktor singleton.
Eventhandler of PropertyChanged
melewati contoh ISingleton
sebagai argumen pertama, dan sebagai parameter kedua contoh SingletonPropertyEventArgs
, yang berisi properti berikut:
Name
: String yang berisi nama properti yang diubahValue
: Nilai arus kotak propertiProperty
: Properti yang dikodekan sebagai nilai enum SingletonProperty
Kutipan kode berikut membuat contoh SingletonPropertyEventArgs
baru:
var propertyName = SingletonProperty . Instance . ToString ( ) ;
var propertyValue = 100 ;
var args = new SingletonPropertyEventArgs ( SingletonProperty . Initialized , propertyValue ) ;
Contoh berikut menunjukkan penggunaan dinamis GetValue
dalam Eventhandler, untuk mengakses properti singleton yang tidak diketahui sampai runtime.
Singelton < MyClass > . PropertyChanged += ( sender , arg ) =>
{
if ( arg . Property == SingletonProperty . Initialized )
{
var value = sender . GetValue ( " Value " ) ;
}
} ;
Secara umum, disarankan untuk properti ACCSS dari singleton serupa melalui antarmuka kustom (yaitu ISingletonTemplate<TCommonDenominator>
) dan melakukan typecheck spesifik menggunakan is
di samping gips eksplisit:
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
}
} ;
Dalam contoh berikut kelas AClass
mengimplementasikan 'Logika Bisnis Singleton', dan mewarisi dari Singleton<>
.
Cukuplah untuk memasukkan rakitan, namespaces dan derivasi : Singleton<AClass>
untuk mendapatkan perilaku yang diharapkan dan diuji:
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 ) ;
}
Catatan: Banyak contoh lagi disediakan secara penuh, di dalam folder Contoh.
Contoh di atas ini akan menghasilkan hasil yang diharapkan dari:
Running: Examples.Example1. Press any key to quit...
Expected: ' Main ' ; Observed: ' Main '
Expected: ' Main ' ; Observed: ' Main '
Expected: ' Main ' ; Observed: ' Main '
Kelas singleton dapat melempar SingletonException
(lihat Gambar 1).
Ini dirujuk dalam 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 ,
Untuk inisialisasi global serta penyempitan tujuan singleton, kelas singleton logis harus selalu dikaitkan dengan [Singleton]
seperti yang ditunjukkan dalam contoh kode berikut:
[ Singleton ( disposable : false , initByAttribute : false , createInternal : true ) ]
public class AClass : Singleton < AClas > {
.. .
}
Atribut memiliki tiga properti yang dapat diakses:
Disposable
(default = false): diatur ke true
jika diizinkan untuk dibuangCreateInternal
(default = true): Setel ke false
jika singleton hanya seharusnya dipakai secara eksternal dengan deklarasi eksplisit dalam kode sumber penggunaInitByAttribute
(default = true): Setel ke true
untuk memungkinkan inisialisasi bersama dengan metode SingletonManager
Initialize
Untuk mengelola beberapa jenis dan instance singleton di seluruh aplikasi besar, gunakan kelas SingletonManager
sebagai berikut:
Contoh berikut ini mengulangi Pool
singleton dan melakukan logika tergantung pada jenis 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);
}
}
Properti singletonManager.Pool
menyediakan akses ke instance yang aman, ConcurrentDictionary<Type, ISingleton>
yang memungkinkan untuk menulis kueri dalam sintaks LINQ yang sudah dikenal.
Singleton yang dibuang tidak pernah dihapus tetapi diatur ke null
menggunakan metode AddOrUpdate
singletonManager.
Untuk membuat instance baru dari tipe yang diketahui, gunakan metode CreateTance generik sebagai berikut:
var singletonManager = new SingletonManager ( ) ;
var gameStatics = singletonManager . CreateSingleton < GameStatics > ( ) ;
Jika jenisnya hanya diketahui saat runtime atau tersedia secara dinamis lulus tipe sebagai argumen, seperti yang ditunjukkan pada contoh kode berikut:
var singletonManager = new SingletonManager ( ) ;
var getInstance = ( type ) => {
var gameStatics = singletonManager . CreateSingleton ( type ) ;
} ;
getInstance ( typeof ( GameStatics ) ) ;
Tidak ada di kelas singleton itu sendiri yang akan mencegah implementasi serializer, namun implementasi serta pengujian ada di tangan pengembang.
Solusi generik tidak direkomendasikan tetapi lebih spesifik, implementasi yang diuji dari singleton jika diperlukan. Misalnya dalam skenario status hibernate / resume. Disarankan untuk menggunakan Extend The SingletonManager untuk tujuan itu.
Lihat juga diskusi ini
Perpustakaan ini telah diuji oleh kerangka pengujian Xunit. Tes dijalankan dengan beberapa kelas, salah satu dengan AClass
menganut skema warisan kanonik langsung:
Gambar 1:
Jika Anda yakin bahwa Anda bertemu dengan bug, silakan dorong masalah baru di sini.
Dalam skenario warisan bersarang dari beberapa kelas yang mewarisi satu sama lain secara hierarkis, dan kelas dasar yang ditentukan yang berasal dari singleton, penting untuk mendefinisikan kelas singleton logis. Ini adalah kelas yang dimaksudkan untuk mengimplementasikan logika SingleOtn yang mengikuti Pricipal Tanggung Jawab Tunggal.
Itu juga kelas yang menentukan tipe T
generik dari mana kelas dasar - kelas pendek Singleton<T>
sendiri, harus mewarisi Singleton<T>
Untuk skenario singleton warisan yang lebih kompleks, silakan merujuk ke README_Example_Advanced.md
Untuk mempertahankan keterbacaan yang baik saat menggunakan perpustakaan ini:
singleton<T>
: misalnya ParentOfParentOfAClass.Instance
tidak apa -apa, tetapi hindari AClass.Instance
SingletonAttribute