我的代码:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
public class Program
{
private static void Main(string[] args)
{
var test = new Test(); // TypeInitializationException?
var test2 = new Test();
}
public class Test
{
public Test()
{
Trace.WriteLine("Test Created");
}
static Test()
{
Task.Factory.StartNew(
() =>
{
throw new Exception();
});
}
}
}
如果我将静态const更改为:
static Test()
{
throw new Exception();
}
然后它抛出TypeInitializationException!我认为静态构造函数是线程安全的吗?
Is the C# static constructor thread safe?
private static void Main(string[] args)
{
Task.Factory.StartNew(
() =>
{
var test = new Test();
});
var test2 = new Test(); // HERE I GET THE EXCEPTION!!!!
}
public class Test
{
public Test()
{
Trace.WriteLine("Test Created");
}
static Test()
{
throw new Exception();
}
}
}
答案 0 :(得分:4)
在此上下文中,线程安全只意味着您不必担心两个线程同时调用静态构造函数,或者一个线程启动静态构造函数,另一个线程认为它具有运行并跳过构造函数,即使它还没有完成(导致访问未初始化的字段)。
如果在构造函数中抛出异常,只是一个错误。与线程安全无关。类型初始化错误非常糟糕,并且会一直发生,直到静态构造函数能够成功完成。
答案 1 :(得分:4)
Thread safe is not a particularly helpful phrase to use.您通常应该避免使用它,因为它并没有真正告诉您哪些操作是安全的。
相反,明确说明在任何给定上下文中支持哪些与线程相关的操作和情况非常重要。然后,人们可以客观地,清楚地说明期望是否被违反。
C#将确保静态构造函数在使用之前的某个时刻运行,无论有多少线程可能使用该类,或者另一个线程当前是否正在运行静态构造函数。
C#将确保它不会多次运行静态构造函数,无论有多少不同的线程可能在同一时间使用同一个类,或者另一个线程是否在当前使用类被初始化。
规范具体表明如果静态构造函数在它运行的一次中抛出异常,则该类型的所有未来使用将抛出TypeInitializationException
,这就是你的意思看到。
您看到的行为完全符合规范中定义的行为。
答案 2 :(得分:1)
静态构造函数将所有抛出的异常包装到TypeInitializationException
中并且与线程安全无关。
保证构造函数在第一次使用类型之前执行一次(或者如果不使用类型则不执行),而不依赖于访问该类型的线程数。这意味着它是线程安全的。