我有一个带有静态构造函数的类:
private static readonly Dictionary<string, User> UsersByName;
private static readonly Dictionary<string, User> UsersByEmail;
static MyClass() {
List<User> users = GetUsers();
UsersByName = users.ToDictionary(user => user.Name);
UsersByEmail = users.ToDictionary(user => user.Email);
}
private static List<User> GetUsers() { /* Make a WCF service call */ }
我的问题是每当我进行WCF调用时,此Web应用程序中的所有工作线程都会死亡。经过大量的头部刮擦和二进制切割后,我找到了根本原因 - 它发生在我们添加UsersByEmail
时,并将代码移动到静态构造函数中。将代码更改为以下修复的所有内容。
private static readonly List<User> AllUsers = GetUsers();
private static readonly Dictionary<string, User> UsersByName = AllUsers.ToDictionary(user => user.Name);
private static readonly Dictionary<string, User> UsersByEmail = AllUsers.ToDictionary(user => user.Email);
private static List<User> GetUsers() { /* Make a WCF service call */ }
不考虑从静态构造函数调用WCF的糟糕设计(如果服务恰好关闭,它会破坏应用程序直到它重新启动),因为这是临时代码 - 我试图找出更改修复此问题的原因问题。我在调试器中多次运行它,唯一的区别是我添加或删除一个空的静态构造函数;调用堆栈总是相同的意思是同时调用Web服务,所以我没有看到如果没有静态构造函数从类中调用它会有什么不同。
答案 0 :(得分:2)
我记得,beforefieldinit
告诉JIT编译器,在引用任何静态字段之前,可以在任何点运行静态构造函数。
因此,例如,如果首先在for
循环内访问该类,则JIT可能会尝试在 for
循环开始之前静态实例化,因此它不必在for
循环中包含代码来检查它是否在每次迭代期间被实例化。同样,如果方法不接触任何这些属性,则可以在不实际初始化任何静态属性的情况下调用静态方法。
但是如果你包含一个显式的静态构造函数,它会将beforefieldinit
设置为false
,这意味着JIT编译的代码将一直等到for
循环中访问类的那一点在实例化类之前,无论代码是否实际触及任何静态字段,它都会在该点实例化它。
所以简短的回答是,是的,它可能会对你的代码运行的顺序产生影响,但它很少会导致问题,我不知道为什么它会对此产生影响特殊情况。
有关详细信息,请参阅Jon Skeet's answer。