静的コンストラクターの使い方を教えてください。なぜ、いつ静的コンストラクターを作成し、それをオーバーロードすることは可能ですか?
8 に答える
いいえ、オーバーロードすることはできません。静的コンストラクターは、型に関連付けられた静的フィールド(またはその他の型ごとの操作)を初期化するのに役立ちます。特に、必要な構成データを読み取り専用フィールドに読み込む場合などに役立ちます。
初めて必要になったときにランタイムによって自動的に実行されます(正確なルールは複雑で(「beforefieldinit」を参照)、CLR2とCLR4の間で微妙に変更されます)。リフレクションを乱用しない限り、最大で1回実行されることが保証されます(2つのスレッドが同時に到着した場合でも)。
静的コンストラクターから(C#プログラミングガイド):
静的コンストラクターは、静的データを初期化するため、または1回だけ実行する必要がある特定のアクションを実行するために使用されます。最初のインスタンスが作成される前、または静的メンバーが参照される前に、自動的に呼び出されます。
静的コンストラクターには、次のプロパティがあります。
静的コンストラクターは、アクセス修飾子を受け取らないか、パラメーターを持ちません。
静的コンストラクターは、最初のインスタンスが作成される前、または静的メンバーが参照される前に、クラスを初期化するために自動的に呼び出されます。
静的コンストラクターを直接呼び出すことはできません。
ユーザーは、静的コンストラクターがプログラムでいつ実行されるかを制御できません。
静的コンストラクターの一般的な使用法は、クラスがログファイルを使用していて、コンストラクターを使用してこのファイルにエントリを書き込む場合です。
静的コンストラクターは、コンストラクターが
LoadLibrary
メソッドを呼び出すことができる場合に、アンマネージコードのラッパークラスを作成するときにも役立ちます。
静的コンストラクターは、初期化の順序が重要になるように相互に依存する静的フィールドがある場合にも非常に役立ちます。フィールドの順序を変更するフォーマッタ/ビューティファイアを介してコードを実行すると、予期していなかった場所にnull値が表示される場合があります。
例:次のクラスがあるとします。
class ScopeMonitor
{
static string urlFragment = "foo/bar";
static string firstPart= "http://www.example.com/";
static string fullUrl= firstPart + urlFragment;
}
アクセスfullUr
すると「http://www.example.com/foo/bar」になります。
数か月後、コードをクリーンアップしてフィールドをアルファベット順に並べ替えます(たとえば、フィールドがはるかに大きなリストの一部であるため、問題に気付かないとしましょう)。あなたが持っている:
class ScopeMonitor
{
static string firstPart= "http://www.example.com/";
static string fullUrl= firstPart + urlFragment;
static string urlFragment = "foo/bar";
}
設定時に初期化されていなかったため、fullUrl
値は「http://www.example.com/」になりました。良くない。したがって、初期化を処理する静的コンストラクターを追加します。urlFragment
fullUrl
class ScopeMonitor
{
static string firstPart= "http://www.example.com/";
static string fullUrl;
static string urlFragment = "foo/bar";
static ScopeMonitor()
{
fullUrl= firstPart + urlFragment;
}
}
これで、フィールドの順序に関係なく、初期化は常に正しくなります。
1.クラスの静的メンバーにのみアクセスできます。
理由:非静的メンバーはオブジェクトインスタンスに固有です。静的コンストラクターが非静的メンバーでの作業を許可されている場合、すべてのオブジェクトインスタンスの変更が反映されますが、これは実用的ではありません。
2.静的コンストラクターにパラメーターがあってはなりません。
理由:CLRによって呼び出されるため、誰もパラメーターを渡すことができません。3.静的コンストラクターは1つだけ許可されます。
理由:オーバーロードでは、静的コンストラクターでは不可能なメソッド/コンストラクター定義の点で2つのメソッドが異なる必要があります。
4.アクセス修飾子はありません。
理由:ここでも理由は、静的コンストラクターへの呼び出しがオブジェクトではなくCLRによって行われるため、アクセス修飾子が必要ないためです。
静的コンストラクターを使用して、静的フィールドを初期化できます。これらのフィールドが使用される前に、不確定な時間に実行されます。Microsoftのドキュメントと多くの開発者は、型の静的コンストラクターがかなりのオーバーヘッドを課すと警告しています。
パフォーマンスを最大化するには、静的コンストラクターを避けるのが最善です。
更新:同じクラスで複数の静的コンストラクターを使用することはできませんが、(最大)1つの静的コンストラクターで他のインスタンスコンストラクターを使用できます。
なぜ、いつ静的コンストラクターを作成するのでしょうか...?
静的コンストラクターを使用する特定の理由の1つは、「スーパー列挙型」クラスを作成することです。これが(単純で不自然な)例です:
public class Animals
{
private readonly string _description;
private readonly string _speciesBinomialName;
public string Description { get { return _description; } }
public string SpeciesBinomialName { get { return _speciesBinomialName; } }
private Animals(string description, string speciesBinomialName)
{
_description = description;
_speciesBinomialName = speciesBinomialName;
}
private static readonly Animals _dog;
private static readonly Animals _cat;
private static readonly Animals _boaConstrictor;
public static Animals Dog { get { return _dog; } }
public static Animals Cat { get { return _cat; } }
public static Animals BoaConstrictor { get { return _boaConstrictor; } }
static Animals()
{
_dog = new Animals("Man's best friend", "Canis familiaris");
_cat = new Animals("Small, typically furry, killer", "Felis catus");
_boaConstrictor = new Animals("Large, heavy-bodied snake", "Boa constrictor");
}
}
他の列挙型と非常によく似た方法で(構文上の外観で)使用します。
Animals.Dog
通常に対するこれの利点は、enum
関連情報を簡単にカプセル化できることです。1つの欠点は、ステートメントでこれらの値を使用できないことですswitch
(定数値が必要なため)。
Static constructor
作成されたクラスの最初のインスタンスのみを呼び出します。クラスのライフサイクルで一度だけ実行する必要がある特定のアクションを実行するために使用されます。
Microsoftのドキュメントから https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
静的コンストラクター(C#プログラミングガイド)
静的コンストラクターは、静的データを初期化するため、または1回だけ実行する必要がある特定のアクションを実行するために使用されます。最初のインスタンスが作成される前、または静的メンバーが参照される前に、自動的に呼び出されます。
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;
// Static constructor is called at most one time, before any
// instance constructor is invoked or member is accessed.
static SimpleClass()
{
baseline = DateTime.Now.Ticks;
}
}
備考
静的コンストラクターには、次のプロパティがあります。
- 静的コンストラクターは、アクセス修飾子を受け取らないか、パラメーターを持ちません。
- クラスまたは構造体は、静的コンストラクターを1つだけ持つことができます。
- 静的コンストラクターは継承またはオーバーロードできません。
- 静的コンストラクターは直接呼び出すことはできず、共通言語ランタイム(CLR)によってのみ呼び出されるようになっています。自動的に呼び出されます。
- ユーザーは、静的コンストラクターがプログラムでいつ実行されるかを制御できません。
- 静的コンストラクターは自動的に呼び出されます。最初のインスタンスが作成される前、またはそのクラスで宣言された静的メンバー(基本クラスではない)が参照される前に、クラスを初期化します。静的コンストラクターは、インスタンスコンストラクターの前に実行されます。タイプの静的コンストラクターは、イベントまたはデリゲートに割り当てられた静的メソッドが呼び出されたときに呼び出され、割り当てられたときは呼び出されません。静的フィールド変数初期化子が静的コンストラクターのクラスに存在する場合、それらはクラス宣言に表示されるテキストの順序で実行されます。初期化子は、静的コンストラクターの実行の直前に実行されます。
- 静的フィールドを初期化する静的コンストラクターを提供しない場合、すべての静的フィールドは、C#タイプのデフォルト値にリストされているデフォルト値に初期化されます。
- 静的コンストラクターが例外をスローした場合、ランタイムはそれを2回呼び出さず、アプリケーションドメインの存続期間中、型は初期化されないままになります。最も一般的には、静的コンストラクターが型をインスタンス化できない場合、または静的コンストラクター内で発生する未処理の例外の場合に、xref:System.TypeInitializationException例外がスローされます。ソースコードで明示的に定義されていない静的コンストラクターの場合、トラブルシューティングでは中間言語(IL)コードの検査が必要になる場合があります。
- 静的コンストラクターが存在すると、xref:System.Reflection.TypeAttributes.BeforeFieldInit型属性を追加できなくなります。これにより、実行時の最適化が制限されます。
- として宣言されたフィールドは
static readonly
、その宣言の一部として、または静的コンストラクターでのみ割り当てることができます。明示的な静的コンストラクターが必要ない場合は、実行時の最適化を向上させるために、静的コンストラクターを使用するのではなく、宣言時に静的フィールドを初期化します。 - ランタイムは、単一のアプリケーションドメインで静的コンストラクターを1回だけ呼び出します。その呼び出しは、クラスの特定のタイプに基づいてロックされた領域で行われます。静的コンストラクターの本体に追加のロックメカニズムは必要ありません。デッドロックのリスクを回避するために、静的コンストラクターと初期化子で現在のスレッドをブロックしないでください。たとえば、タスク、スレッド、待機ハンドルまたはイベントを待機したり、ロックを取得したり、並列ループ
Parallel.Invoke
や並列LINQクエリなどのブロッキング並列操作を実行したりしないでください。
[!注]直接アクセスすることはできませんが、初期化例外のトラブルシューティングを支援するために、明示的な静的コンストラクターの存在を文書化する必要があります。
使用法
- 静的コンストラクターの一般的な使用法は、クラスがログファイルを使用していて、コンストラクターを使用してこのファイルにエントリを書き込む場合です。
- 静的コンストラクターは、コンストラクターが
LoadLibrary
メソッドを呼び出すことができる場合に、アンマネージコードのラッパークラスを作成するときにも役立ちます。 - 静的コンストラクターは、コンパイル時に型パラメーター制約を介してチェックできない型パラメーターの実行時チェックを実施するための便利な場所でもあります。