著者 | |
---|---|
Webサイト | https://github.com/lsauer/csharp-singleton |
ライセンス | MITライセンス |
現在 | |
パッケージ | PM> Install-Package CSharp.Portable-Singleton |
説明 | 単一インスタンスを実施および管理するための、一般的でポータブルで文書化された、使いやすいシングルトンパターンの実装。 |
ドキュメント | 完全なリファレンスv2.0.0.4 |
サポート |
|
フルバージョン | ヌゲット | 建てる | nugetインストール |
---|---|---|---|
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パターンは、ソフトウェアで作成された設計パターンとして顕著な使用であり、オブジェクトの1つのインスタンスのみがインスタンス化される可能性があるため、一般にシングルトンの有用性が単一アクセスリソースの作成またはラッピングに拡張されます。
新しいシングルトンを作成するのは簡単です。意図したシングルトンクラスの一般的なシングルトンクラスのSingleton<>
の継承を十分に宣言してください。
のような:
internal class MyClass : Singleton < MyClass > {
.. .
}
シングルトンの使用例は、.NETコンソールアプリケーションの改良コンソールラッパーです。その他の典型的なシナリオは、パフォーマンスと同期の側面が耐えられるようなものです。
注:おそらく、最新のプラットフォームで実行されている大規模なアプリケーションは、特に設計パターンのフレームワークサポートを通じて、シングルトンよりも改善されたソリューションに頼ることができます。
開始するには、次の構文を遵守することをお勧めします。
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()
[Singleton]class T : Singleton<T>{...}
などのSingletonAttribute
を使用し、その後Singletonmanager
インスタンスからInitialize()
呼び出すActivator.CreateInstance(typeof(T));
new T(...)
でクラス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()
を使用してください。それぞれ、上記のTypeInfo
にGetTypeInfo()
への呼び出しを省略します。
(Instance == null)
かどうかを確認できます。 次のプロパティは、カスタムタイプのSingletonPropertyEventHandler
を使用しながら、違反のプロパティPropertyChangedEventHandler
の代わりに使用しながら、 INotifyPropertyChanged
の慣習に従いますが、実装しません。
PropertyChanged自体が静的であると宣言され、Singleton Instance自体が処分され、ごみ収集PropertyChanged
ために無料で無料でDisposed
およびInitialized
。
public static event SingletonEventHandler PropertyChanged ;
さらに、プロパティManager
が変更されたときにイベントがトリガーされます。このプロパティは、 ISingletonManager
を実装するSingletonManagerインスタンスのセッター依存噴射に使用されます。
特定のプロジェクトでいくつかのシングルトンクラスの場合、 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
要素を安全にすることが安全であることに注意してください。
PropertyChanged
のイベントハンドラーは、 ISingleton
のインスタンスを最初の引数として通過し、2番目のパラメーターとして、次のプロパティを含むSingletonPropertyEventArgs
のインスタンスを通過します。
Name
:変更されたプロパティの名前を含む文字列Value
:プロパティの箱入りの電流値Property
: SingletonProperty
の列挙値としてエンコードされたプロパティ次のコード抜粋により、新しいSingletonPropertyEventArgs
インスタンスが作成されます。
var propertyName = SingletonProperty . Instance . ToString ( ) ;
var propertyValue = 100 ;
var args = new SingletonPropertyEventArgs ( SingletonProperty . Initialized , propertyValue ) ;
次の例は、実行時まで知られていないSingletonプロパティにアクセスするために、イベントハンドラー内のGetValue
の動的使用を示しています。
Singelton < MyClass > . PropertyChanged += ( sender , arg ) =>
{
if ( arg . Property == SingletonProperty . Initialized )
{
var value = sender . GetValue ( " Value " ) ;
}
} ;
一般に、カスタムインターフェイス(つまり、 ISingletonTemplate<TCommonDenominator>
)を介して同様のシングルトンのACCSSプロパティを推奨し、明示的なキャストと一緒に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 Business Logic」を実装し、 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 '
Singletonクラスは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 > {
.. .
}
属性には3つのアクセス可能なプロパティがあります。
Disposable
(default = false):処分を許可されている場合はtrue
に設定しますCreateInternal
(default = true):singletonがユーザーソースコード内の明示的な宣言によって外部からのみインスタンス化されることになっている場合にfalse
に設定InitByAttribute
(default = true): SingletonManager
メソッドInitialize
による共同初期化を許可するtrue
に設定大規模なアプリケーション全体でいくつかのシングルトンタイプとインスタンスを管理するには、次のように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
Propertyは、おなじみのLINQ構文でクエリを作成できるスレッドセーフ、 ConcurrentDictionary<Type, ISingleton>
インスタンスへのアクセスを提供します。
廃棄されたシングルトンは削除されることはありませんが、SingletonManagerのAddOrUpdate
メソッドを使用してnull
に設定されます。
既知のタイプの新しいインスタンスを作成するには、次のように汎用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 Stateシナリオで。その目的のためにSingletonManagerを拡張することをお勧めします。
また、この議論を見てください
このライブラリは、Xunitテストフレームワークによってテストされています。テストはいくつかのクラスで実行されます。1つは、 AClass
が簡単な砲撃スキーマを順守しています。
図1:
バグに遭遇したことを確認した場合は、ここで新しい問題を推進してください。
階層的に互いに継承するいくつかのクラスのネストされた継承シナリオと、シングルトンに由来する決定的な基本クラスでは、論理的なシングルトンクラスを定義することが重要です。これは、単一の責任価格に続くシングルオットのロジックを実装することを目的としたクラスです。
それはまた、基本クラス( Singleton<T>
の略クラス)を決定する一般的なタイプT
を決定するクラスであり、 Singleton<T>
を継承する必要があります
より複雑な継承シングルトンシナリオについては、 README_Example_Advanced.md
を参照してください
このライブラリを使用するときに適切な読みやすさを維持するには:
singleton<T>
:例えばParentOfParentOfAClass.Instance
はAClass.Instance
を避けてくださいSingletonAttribute
を使用して、シングルトンの目的に従ってシングルトンクラスを属性