9

まず、What is the use of static constructors? で答えを得ました。、しかし、この文脈で答えが欲しいです。

これが私の C# 静的クラスです。

public static class BasicClass
{
    static int i = 0;
    static BasicClass()
    {
        i = 10;
    }

    public static void Temp()
    {
        //some code
    }


    public static void Temp1()
    {
        //some code
    }
}

iこの内部には、最初に呼び出されたときに 10 に初期化される静的変数があります。したがって、基本的には静的コンストラクターの目的である可能性がありますが、同じ目的を果たすものを初期化することにより、静的コンストラクターを宣言せずに同じことを達成できます。static int i = 10 これは一度だけ初期化されます。

では、なぜ静的コンストラクターが必要なのでしょうか? それとも、静的コンストラクターの概念や使用法を完全に理解していないのでしょうか?

4

8 に答える 8

23

そのクラスをアセンブリにコンパイルし、ILSpy などを使用して結果を逆アセンブルすると、すべての静的メンバーの初期化が静的コンストラクターで実行されることがわかります。

たとえば、次の C# コードは次のとおりです。

public static class BasicClass
{
    static int i = 10;
}

以下に相当する IL を生成します。

public static class BasicClass
{
    static int i;

    static BasicClass()
    {
        i = 10;
    }
}

言い換えれば、直接初期化は、C# コンパイラによって提供されるシンタックス シュガーにすぎません。内部では、静的コンストラクターがまだ実装されています。

于 2013-03-06T14:38:39.330 に答える
6

あなたの例では実際には必要ありませんが、データベース、テキスト ファイル、またはその他のリソースから値を読み取る必要がある場合を想像してiみてください。次のようなものが必要になる場合があります。

static BasicClass()
{
    using (SomeConnection con = Provider.OpenConnection())
    {
        try
        {
            // Some code here
        }
        catch
        {
            // Handling expeptions, setting default value
            i = 10;
        }
    }
}

静的フィールドを宣言して初期化することはできなくなりました。静的コンストラクターを使用することをお勧めします。

于 2013-03-06T14:38:52.213 に答える
1

このシナリオでは、静的コンストラクターは必要ありません。

static BasicClass()
{
    i = 10;
}

static int i = 10;

機能的に同一です。

于 2013-03-06T14:38:28.583 に答える
1

答えはリンクされた質問にもあります:

[...] 特に、必要な構成データを読み取り専用フィールドなどに読み込む場合に役立ちます。

これは、初めて必要になったときにランタイムによって自動的に実行されます (正確なルールは複雑で (「beforefieldinit」を参照)、CLR2 と CLR4 の間で微妙に変更されています)。>リフレクションを悪用しない限り、(たとえ 2 つのスレッドが同時に到着したとしても) せいぜい 1 回しか実行されないことが保証されます。

データベース接続の設定など、静的コンストラクターではるかに複雑なものを初期化できます。それが理にかなっているなら、それは別のことです...

于 2013-03-06T14:39:19.097 に答える
1

静的コンストラクターは、コンストラクター内でいくつかのアクションを実行する必要があり、アプリケーションで一意のインスタンスが必要な場合に意味があります。例えば:

public static class BasicClass
{
    static MyConfiguration _myConfig;

    static BasicClass()
    {
       // read configuration from file
       _myConfig = ReadConfigFromConfigFile("somefile.conf");
    }

    private static MyConfiguration ReadConfigFromConfigFile(string file)
    {
       using (StreamReader reader = new StreamReader(file);
       {
         ...
       }
    }
}

あなたが説明したシナリオでは、明示的に静的コンストラクターは必要ありません。

また、シングルトン パターンを適用して、この目的を達成することもできます。

于 2013-03-06T14:39:59.173 に答える
0

コンパイル時の定数でのみフィールドを初期化できます(あなたの場合)。ただし、静的コンストラクターでは、一部のコードを実行できます (構成ファイルの読み取りなど)。

于 2013-03-06T14:37:43.607 に答える
0

静的コンストラクターは、変数を初期化する目的を果たすだけでなく、(静的) クラス (または環境) が動作し、それらのオブジェクトまたはクラス自体でメソッドを呼び出すために必要なオブジェクトを作成します。

于 2013-03-06T14:39:00.700 に答える
0

foo()まだ言及されていない要因の 1 つは、(コンストラクター構文を使用して記述された) 静的コンストラクターの呼び出しと、静的フィールド初期化子の呼び出しとの間に意味上の違いがあることです。特に、型にコンストラクター構文を使用して記述された静的コンストラクターがある場合、そのコンストラクターは、その型を「使用する」コードが実行される最初の時間に呼び出されることが保証されます。その前に呼び出されることはなく、型が使用されていない場合は呼び出されません。対照的に、.NET は型の静的フィールド初期化子がその静的フィールドのいずれかにアクセスされる前に実行され、2 回以上実行されないことを保証しますが、.NET は、型取得される可能性があると最初に判断したときに、そのような静的初期化子を自由に実行できます。使用済み。たとえば、次のように考えてください。

if (someCondition())
  for (i=0; i<100000000; i++)
    someClass.someStaticField++;

Just-In-Time コンパイラが上記のコードに遭遇したときに、someClass一度も使用されておらず、静的コンストラクター構文を使用して宣言されたコンストラクターがある場合、結果のマシン コードは次のようになります。

if (someCondition())
  for (i=0; i<100000000; i++)
  {
    if (someClass.hasBeenInitialized)
      someClass.runConstructor();
    someClass.someStaticField++;
  }

ループ内でif-check を実行します。対照的に、フィールドの初期化があり、コンストラクター スタイルの宣言がない場合、JIT はコードを実行する前に静的な構築を実行する可能性が高いため、コード内にチェックsomeClassを含める必要がなくなります。if

于 2013-10-28T22:53:46.177 に答える