本文提供了此 API 参考文档的补充说明。
当类初始值设定项无法初始化类型时,将创建 a TypeInitializationException 并传递对该类型的类初始值设定项引发的异常的引用。 InnerException的 TypeInitializationException 属性保存着基础异常。
通常, TypeInitializationException 异常反映灾难性条件(运行时无法实例化类型),以防止应用程序继续。 通常情况下,TypeInitializationException 是在应用程序执行环境发生某些变化时引发的。 因此,除了可能用于对调试代码进行故障排除之外,不应在块中 try
/catch
处理异常。 相反,应调查并消除异常的原因。
TypeInitializationException 使用具有值0x80131534的 HRESULT COR_E_TYPEINITIALIZATION
。
有关实例 TypeInitializationException的初始属性值列表,请参阅 TypeInitializationException 构造函数。
以下部分介绍引发 TypeInitializationException 异常的一些情况。
静态构造函数
静态构造函数(如果存在)在创建类型的新实例之前由运行时自动调用。 静态构造函数可由开发人员显式定义。 如果未显式定义静态构造函数,编译器会自动创建一个来初始化类型的任何 static
(在 C# 或 F# 中)或 Shared
(在 Visual Basic 中)成员。 有关静态构造函数的详细信息,请参阅 静态构造函数。
通常, TypeInitializationException 当静态构造函数无法实例化类型时,将引发异常。 该 InnerException 属性指示静态构造函数无法实例化类型的原因。 TypeInitializationException 异常的一些更常见的原因包括:
静态构造函数中的未经处理的异常
如果在静态构造函数中引发异常,该异常将会被包装在TypeInitializationException异常中,并且无法实例化该类型。
通常使此异常难以进行故障排除的是,静态构造函数并不总是在源代码中显式定义。 在某个类型中存在静态构造函数的条件是:
它已显式定义为类型的成员。
该类型具有
static
(在 C# 或 F# 中)或Shared
(在 Visual Basic 中)变量,这些变量在单个语句中声明和初始化。 在这种情况下,语言编译器为类型生成静态构造函数。 可以使用 IL 反汇编程序等实用工具对其进行检查。 例如,当 C# 和 VB 编译器编译以下示例时,它们将为类似于下面的静态构造函数生成 IL:
.method private specialname rtspecialname static void .cctor() cil managed { // Code size 12 (0xc) .maxstack 8 IL_0000: ldc.i4.3 IL_0001: newobj instance void TestClass::.ctor(int32) IL_0006: stsfld class TestClass Example::test IL_000b: ret } // end of method Example::.cctor
以下示例演示 TypeInitializationException 编译器生成的静态构造函数引发的异常。 该
Example
类包含一个字段:在 C# 中是static
,在 Visual Basic 中是Shared
,其字段类型为TestClass
,并通过向类构造函数传递值 3 来实例化。 然而,该值是非法的;仅允许 0 或 1 的值。 因此,TestClass
类构造函数将抛出ArgumentOutOfRangeException。 由于此异常未被处理,因此它被包装在一个 TypeInitializationException 异常中。using System; public class Example { private static TestClass test = new TestClass(3); public static void Main() { Example ex = new Example(); Console.WriteLine(test.Value); } } public class TestClass { public readonly int Value; public TestClass(int value) { if (value < 0 || value > 1) throw new ArgumentOutOfRangeException(nameof(value)); Value = value; } } // The example displays the following output: // Unhandled Exception: System.TypeInitializationException: // The type initializer for 'Example' threw an exception. ---> // System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. // at TestClass..ctor(Int32 value) // at Example..cctor() // --- End of inner exception stack trace --- // at Example.Main()
Public Class Example1 Shared test As New TestClass(3) Public Shared Sub Main() Dim ex As New Example1() Console.WriteLine(test.Value) End Sub End Class Public Class TestClass Public ReadOnly Value As Integer Public Sub New(value As Integer) If value < 0 Or value > 1 Then Throw New ArgumentOutOfRangeException(NameOf(value)) value = value End Sub End Class ' The example displays the following output: ' Unhandled Exception: System.TypeInitializationException: ' The type initializer for 'Example' threw an exception. ---> ' System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. ' at TestClass..ctor(Int32 value) ' at Example..cctor() ' --- End of inner exception stack trace --- ' at Example.Main()
请注意,异常消息显示有关 InnerException 属性的信息。
缺少程序集或数据文件
TypeInitializationException 异常的常见原因是应用程序开发和测试环境中存在的程序集或数据文件在其运行时环境中缺失。 例如,可以使用以下命令行语法将以下示例编译为名为 Missing1a.dll 的程序集:
csc -t:library Missing1a.cs
fsc --target:library Missing1a.fs
vbc Missing1a.vb -t:library
using System; public class InfoModule { private DateTime firstUse; private int ctr = 0; public InfoModule(DateTime dat) { firstUse = dat; } public int Increment() { return ++ctr; } public DateTime GetInitializationTime() { return firstUse; } }
open System type InfoModule(firstUse: DateTime) = let mutable ctr = 0 member _.Increment() = ctr <- ctr + 1 ctr member _.GetInitializationTime() = firstUse
Public Class InfoModule Private firstUse As DateTime Private ctr As Integer = 0 Public Sub New(dat As DateTime) firstUse = dat End Sub Public Function Increment() As Integer ctr += 1 Return ctr End Function Public Function GetInitializationTime() As DateTime Return firstUse End Function End Class
然后,可以通过包括对 Missing1a.dll的引用,将以下示例编译为名为 Missing1.exe 的可执行文件:
csc Missing1.cs /r:Missing1a.dll
vbc Missing1.vb /r:Missing1a.dll
但是,如果重命名、移动或删除 Missing1a.dll 并运行该示例,则会引发异常 TypeInitializationException 并显示示例中所示的输出。 请注意,异常消息包含有关 InnerException 该属性的信息。 在这种情况下,内部异常是运行时找不到依赖程序集而引发的 FileNotFoundException。
using System; public class MissingEx1 { public static void Main() { Person p = new Person("John", "Doe"); Console.WriteLine(p); } } public class Person { static readonly InfoModule s_infoModule; readonly string _fName; readonly string _lName; static Person() { s_infoModule = new InfoModule(DateTime.UtcNow); } public Person(string fName, string lName) { _fName = fName; _lName = lName; s_infoModule.Increment(); } public override string ToString() { return string.Format("{0} {1}", _fName, _lName); } } // The example displays the following output if missing1a.dll is renamed or removed: // Unhandled Exception: System.TypeInitializationException: // The type initializer for 'Person' threw an exception. ---> // System.IO.FileNotFoundException: Could not load file or assembly // 'Missing1a, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // or one of its dependencies. The system cannot find the file specified. // at Person..cctor() // --- End of inner exception stack trace --- // at Person..ctor(String fName, String lName) // at Example.Main()
open System type Person(fName, lName) = static let infoModule = InfoModule DateTime.UtcNow do infoModule.Increment() |> ignore override _.ToString() = $"{fName} {lName}" let p = Person("John", "Doe") printfn $"{p}" // The example displays the following output if missing1a.dll is renamed or removed: // Unhandled Exception: System.TypeInitializationException: // The type initializer for 'Person' threw an exception. ---> // System.IO.FileNotFoundException: Could not load file or assembly // 'Missing1a, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // or one of its dependencies. The system cannot find the file specified. // at Person..cctor() // --- End of inner exception stack trace --- // at Person..ctor(String fName, String lName) // at Example.Main()
Module Example3 Public Sub Main() Dim p As New Person("John", "Doe") Console.WriteLine(p) End Sub End Module Public Class Person Shared infoModule As InfoModule Dim fName As String Dim mName As String Dim lName As String Shared Sub New() infoModule = New InfoModule(DateTime.UtcNow) End Sub Public Sub New(fName As String, lName As String) Me.fName = fName Me.lName = lName infoModule.Increment() End Sub Public Overrides Function ToString() As String Return String.Format("{0} {1}", fName, lName) End Function End Class ' The example displays the following output if missing1a.dll is renamed or removed: ' Unhandled Exception: System.TypeInitializationException: ' The type initializer for 'Person' threw an exception. ---> ' System.IO.FileNotFoundException: Could not load file or assembly ' 'Missing1a, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' ' or one of its dependencies. The system cannot find the file specified. ' at Person..cctor() ' --- End of inner exception stack trace --- ' at Person..ctor(String fName, String lName) ' at Example.Main()
注释
在此示例中, TypeInitializationException 由于无法加载程序集,因此引发了异常。 如果静态构造函数尝试打开数据文件(例如配置文件、XML 文件或包含序列化数据的文件)但无法找到,则也可能引发异常。
正则表达式匹配超时值
可以为每个应用程序域设置正则表达式模式匹配操作的默认超时值。 超时是通过为 TimeSpan 方法指定“REGEX_DEFAULT_MATCH_TIMEOUT”属性的 AppDomain.SetData 值来定义的。 时间间隔必须是大于零且小于大约 24 天的有效 TimeSpan 对象。 如果未满足这些要求,则尝试设置默认超时值会引发一个ArgumentOutOfRangeException异常,该异常又会被包装在一个TypeInitializationException异常中。
以下示例显示分配给“REGEX_DEFAULT_MATCH_TIMEOUT”属性的值无效时引发的 TypeInitializationException 值。 若要消除异常,请将“REGEX_DEFAULT_MATCH_TIMEOUT”属性设置为 TimeSpan 大于零且小于大约 24 天的值。
using System;
using System.Text.RegularExpressions;
public class RegexEx1
{
public static void Main()
{
AppDomain domain = AppDomain.CurrentDomain;
// Set a timeout interval of -2 seconds.
domain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromSeconds(-2));
Regex rgx = new Regex("[aeiouy]");
Console.WriteLine($"Regular expression pattern: {rgx.ToString()}");
Console.WriteLine($"Timeout interval for this regex: {rgx.MatchTimeout.TotalSeconds} seconds");
}
}
// The example displays the following output:
// Unhandled Exception: System.TypeInitializationException:
// The type initializer for 'System.Text.RegularExpressions.Regex' threw an exception. --->
// System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
// Parameter name: AppDomain data 'REGEX_DEFAULT_MATCH_TIMEOUT' contains an invalid value or
// object for specifying a default matching timeout for System.Text.RegularExpressions.Regex.
// at System.Text.RegularExpressions.Regex.InitDefaultMatchTimeout()
// at System.Text.RegularExpressions.Regex..cctor()
// --- End of inner exception stack trace ---
// at System.Text.RegularExpressions.Regex..ctor(String pattern)
// at Example.Main()
open System
open System.Text.RegularExpressions
let domain = AppDomain.CurrentDomain
// Set a timeout interval of -2 seconds.
domain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromSeconds -2)
let rgx = Regex "[aeiouy]"
printfn $"Regular expression pattern: {rgx}"
printfn $"Timeout interval for this regex: {rgx.MatchTimeout.TotalSeconds} seconds"
// The example displays the following output:
// Unhandled Exception: System.TypeInitializationException:
// The type initializer for 'System.Text.RegularExpressions.Regex' threw an exception. --->
// System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
// Parameter name: AppDomain data 'REGEX_DEFAULT_MATCH_TIMEOUT' contains an invalid value or
// object for specifying a default matching timeout for System.Text.RegularExpressions.Regex.
// at System.Text.RegularExpressions.Regex.InitDefaultMatchTimeout()
// at System.Text.RegularExpressions.Regex..cctor()
// --- End of inner exception stack trace ---
// at System.Text.RegularExpressions.Regex..ctor(String pattern)
// at Example.Main()
Imports System.Text.RegularExpressions
Module Example4
Public Sub Main()
Dim domain As AppDomain = AppDomain.CurrentDomain
' Set a timeout interval of -2 seconds.
domain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromSeconds(-2))
Dim rgx As New Regex("[aeiouy]")
Console.WriteLine("Regular expression pattern: {0}", rgx.ToString())
Console.WriteLine("Timeout interval for this regex: {0} seconds",
rgx.MatchTimeout.TotalSeconds)
End Sub
End Module
' The example displays the following output:
' Unhandled Exception: System.TypeInitializationException:
' The type initializer for 'System.Text.RegularExpressions.Regex' threw an exception. --->
' System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
' Parameter name: AppDomain data 'REGEX_DEFAULT_MATCH_TIMEOUT' contains an invalid value or
' object for specifying a default matching timeout for System.Text.RegularExpressions.Regex.
' at System.Text.RegularExpressions.Regex.InitDefaultMatchTimeout()
' at System.Text.RegularExpressions.Regex..cctor()
' --- End of inner exception stack trace ---
' at System.Text.RegularExpressions.Regex..ctor(String pattern)
' at Example.Main()
日历和文化数据
如果尝试实例化日历,但运行时无法实例化 CultureInfo 对应于该日历的对象,则会引发异常 TypeInitializationException 。 以下日历类构造函数可以引发此异常:
- JapaneseCalendar 类的无参数构造函数。
- KoreanCalendar 类的无参数构造函数。
- TaiwanCalendar 类的无参数构造函数。
由于这些区域性的文化数据应该在所有系统上都可用,因此很少遇到此异常(如果有的话)。