除了静态构造函数执行的时间之外,beforefieldinit可以有什么影响吗?

时间:2011-07-19 21:34:13

标签: c#

我有一个带有静态构造函数的类:

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服务,所以我没有看到如果没有静态构造函数从类中调用它会有什么不同。

1 个答案:

答案 0 :(得分:2)

我记得,beforefieldinit告诉JIT编译器,在引用任何静态字段之前,可以在任何点运行静态构造函数。

因此,例如,如果首先在for循环内访问该类,则JIT可能会尝试在 for循环开始之前静态实例化,因此它不必在for循环中包含代码来检查它是否在每次迭代期间被实例化。同样,如果方法不接触任何这些属性,则可以在不实际初始化任何静态属性的情况下调用静态方法。

但是如果你包含一个显式的静态构造函数,它会将beforefieldinit设置为false,这意味着JIT编译的代码将一直等到for循环中访问类的那一点在实例化类之前,无论代码是否实际触及任何静态字段,它都会在该点实例化它。

所以简短的回答是,是的,它可能会对你的代码运行的顺序产生影响,但它很少会导致问题,我不知道为什么它会对此产生影响特殊情况。

有关详细信息,请参阅Jon Skeet's answer