質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

3050閲覧

静的フィールドの初期化タイミングについて

stackover

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

1クリップ

投稿2021/11/20 12:31

編集2021/11/20 12:33

下記ソースの出力が A.call1 => False であることから、静的フィールドの初期化タイミングはフィールドの種別やクラスの依存関係によって優先度が異なることが分かります。

CSharp

1class A { 2 public static bool call3 = B.call4; 3 public static bool call1 = B.call2; 4} 5 6 class B { 7 public static bool call4 = C.call5; 8 public static bool call2 = A.call3; 9} 10 11class C { 12 public static bool call5 = true; 13} 14 15class Program { 16 static void Main(string[] args) { 17 18 Console.WriteLine("A.call1 => " + A.call1); // False 19 Console.ReadLine(); 20 } 21}

MSDNではこれらのスコアリングルールについて一切言及していません。
フィールドの初期化優先度はどのように決定しますか?

検証環境

.NET 5.0
Visual Studio 2019 Community
Windows 10

fana👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

stackover

2021/11/20 13:35

完全に理解できました。 ありがとうございます。
guest

回答2

0

既に解決済みみたいですが、全くわかりませんでした。Cから先に宣言してみても結果変わらず。

実行順序がわかりやすくなるように少し手を加えてみました。

https://dotnetfiddle.net/uXPjY2

cs

1using System; 2 3static class C { 4 static C() {} 5 public static bool call5 = Program.F(true, "C.call5"); 6} 7 8static class B { 9 static B() {} 10 public static bool call4 = Program.F(C.call5, "B.call4"); 11 public static bool call2 = Program.F(A.call3, "B.call2"); 12} 13 14static class A { 15 static A() {} 16 public static bool call3 = Program.F(B.call4, "A.call3"); 17 public static bool call1 = Program.F(B.call2, "A.call1"); 18} 19 20public class Program 21{ 22 public static void Main() 23 { 24 Console.WriteLine("A.call1 => " + A.call1); // False 25 } 26 27 public static bool F(bool b, string s) 28 { 29 Console.WriteLine(s); 30 return b; 31 } 32}

実行結果

cs

1C.call5 2B.call4 3B.call2 4A.call3 5A.call1 6A.call1 => False

IL 逆コンパイル結果

https://sharplab.io/#v2:C4LglgNgNAJiDUAfAAgJgIwFgBQPnoDYACNIgQSIG8cjaSBmEwogIwHs2IiBjAQwgiMAvEQBCAOj4CALAG4adZI3zF2nHvwjoiIiVIip52AL448zUqKoLaSpqo5d90nUQDCkzQFYjdBvdZHDQFUVzJPAXojU1xsFRJQt2tsPzt4tSdvV2AAJwBXAFNoszjlUPwAdhxqbABINFQcWpra+vQATgAKACJw/W0hAD4ibqJ4cgitAEpZIgB6OaIAMX4AZwKmmOMgA

C#仕様書

15.5.6.2 Static field initialization
15.12 Static constructors

https://www.ecma-international.org/wp-content/uploads/ECMA-334_5th_edition_december_2017.pdf

投稿2021/11/20 13:46

tor4kichi

総合スコア769

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

stackover

2021/11/20 14:32 編集

下記コードで示すように、それぞれの値までトレースすると理解が捗りました。 ```csharp public static bool F(bool b, string s) { Console.WriteLine(s + " => " + b); return b; } // C.call5 => True // B.call4 => True // B.call2 => False // A.call3 => True // A.call1 => False ``` ログを見る限りでは、フィールドが個々に初期化されるわけではなく、クラスが参照された時点で順次静的フィールドが初期化されるみたいです。 少し掘り下げて説明すると、呼び出し順序でいうとクラスAの初期化開始が先ですが、Aの初期化が完了する前に依存クラスBを初期化しようとしてしまい、B.call2 が A.call3 を参照したときはまだ値が入っていない訳ですね。
tor4kichi

2021/11/21 00:05

寝起きの頭で整理したら納得いきました。補足ありがとうございました!
stackover

2021/11/21 04:34 編集

MSDNの説明だけでは到底理解できない内容ですよね。 私も実際の挙動を確認してやっと理解できました。
guest

0

自己解決

「静的コンストラクター (C# プログラミング ガイド)」

https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
この中に
「静的フィールド変数初期化子が静的コンストラクターのクラスに存在する場合、
それらは、クラス宣言に出現するテキストの順序で実行されます。 」
という記述があります。

Thanks. KOZ6.0.

投稿2021/11/20 13:40

stackover

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問