Code Fix

上級

TypeInitializationException の原因と直し方

静的コンストラクタ(staticフィールドの初期化を含む)の中で例外が起きると、直接の例外ではなくTypeInitializationExceptionに包まれて報告されます。

エラーメッセージの読み方

Unhandled exception. System.TypeInitializationException: The type initializer for 'Settings' threw an exception.
System
名前空間 — System なら標準の基本例外です
TypeInitializationException
例外クラス — 何が起きたか。ここを検索するのが最短です
The type initializer for 'Settings' threw an exception.
詳細メッセージ — どの値が問題だったか
at Settings..cctor() in Program.cs:line 5
発生箇所 — スタックトレースの先頭行

このエラーが出る典型パターン

パターン1

 1  class Settings {
 2      public static int Value;
 3      static Settings() {
 4          int denom = 0;
                        ^
 5          Value = 100 / denom;
 6      }
 7  }
 8  class Program {
 9      static void Main(string[] args) {
10          System.Console.WriteLine(Settings.Value);
11      }
12  }
Unhandled exception. System.TypeInitializationException: The type initializer for 'Settings' threw an exception. at Settings..cctor() in Program.cs:line 5

静的コンストラクタの中で例外が起きると、直接の例外ではなくTypeInitializationExceptionに包まれて報告されます。原因は内側のInnerExceptionにあります。

直し方: 0 を 2 にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  class Catalog {
 2      public static string FirstItem;
 3      static Catalog() {
 4          string[] items = { "pen", "cup" };
 5          FirstItem = items[5 ];
                               ^
 6      }
 7  }
 8  class Program {
 9      static void Main(string[] args) {
10          System.Console.WriteLine(Catalog.FirstItem);
11      }
12  }
Unhandled exception. System.TypeInitializationException: The type initializer for 'Catalog' threw an exception. at Catalog..cctor() in Program.cs:line 5

IndexOutOfRangeExceptionのような別の例外でも、静的コンストラクタ内で起きた時点でTypeInitializationExceptionに包まれます。

直し方: 5 を 0 にします。

この問題を解いてみる →

パターン3

 1  class Parser {
 2      public static int Parsed;
 3      static Parser() {
 4          Parsed = int.Parse("N/A");
                                 ^
 5      }
 6  }
 7  class Program {
 8      static void Main(string[] args) {
 9          System.Console.WriteLine(Parser.Parsed);
10      }
11  }
Unhandled exception. System.TypeInitializationException: The type initializer for 'Parser' threw an exception. at Parser..cctor() in Program.cs:line 4

FormatExceptionが原因でも同じです。静的コンストラクタの中で投げられた例外は種類を問わずTypeInitializationExceptionに包まれます。

直し方: "N/A" を "42" にします。

この問題を解いてみる →

パターン4

 1  class Cache {
 2      public static int Total;
 3      static Cache() {
 4          int[] data = { 1, 2, 3 };
 5          Total = data[9 ];
                          ^
 6      }
 7  }
 8  class Program {
 9      static void Main(string[] args) {
10          System.Console.WriteLine(Cache.Total);
11      }
12  }
Unhandled exception. System.TypeInitializationException: The type initializer for 'Cache' threw an exception. at Cache..cctor() in Program.cs:line 5

配列の範囲外アクセスが原因でも、静的コンストラクタ内であればTypeInitializationExceptionに包まれます。

直し方: 9 を 1 にします。

この問題を解いてみる →

パターン5

 1  class Loader {
 2      public static int Code;
 3      static Loader() {
 4          Code = int.Parse("xx" );
                               ^
 5      }
 6  }
 7  class Program {
 8      static void Main(string[] args) {
 9          System.Console.WriteLine(Loader.Code);
10      }
11  }
Unhandled exception. System.TypeInitializationException: The type initializer for 'Loader' threw an exception. at Loader..cctor() in Program.cs:line 4

FormatExceptionが原因でも、静的コンストラクタの中で起きればTypeInitializationExceptionに包まれます。

直し方: "xx" を "7" にします。

この問題を解いてみる →

よくある誤解

スタックトレースの一番外側だけを見るとTypeInitializationExceptionが原因に見えますが、本当の原因は「--->」で示される内側の例外(InnerException)にあります。

実務での勘所

静的コンストラクタは、その型が実際に初めて使われた瞬間に一度だけ実行される、という遅延初期化の仕組みで動いています(Javaのstatic初期化ブロックと同じ考え方です)。この一度きりの初期化のどこで例外が起きても、呼び出し元(その型を使おうとした、静的コンストラクタの定義とは全く違う場所のコード)が一貫した形で例外を受け取れるように、CLRはどんな例外が飛んできてもTypeInitializationExceptionという共通の型で包み直して報告します。本当の原因はInnerExceptionの中に保存されているという設計です。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)