Can beforefieldinit have any effect other than time of static constructor execution?
I have a class with a static constructor:
private static readonly Dictionary<string, User> UsersByName;
private static rea开发者_如何转开发donly 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 */ }
My problem was that whenever I made that WCF call, all of the worker threads in this web application died. After a lot of head scratching and binary chopping I found the root cause - it happened when we added UsersByEmail
, and moved the code into a static constructor. Changing the code to the following fixed everything.
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 */ }
Leaving aside the bad design of calling WCF from a static constructor (which break the app until it's restarted if the service happens to be down), because that is temporary code - I'm trying to find out why the change fix this problem. I ran it in the debugger many times, with the only difference being me adding or removing an empty static constructor; the call stack is always the same meaning the web service is called at the same time, so I don't see how being called from a class without a static constructor could make any difference.
As I recall, beforefieldinit
tells the JIT compiler that the static constructor can be run at any point before any static fields are referenced.
So, for example, if the class was first accessed inside a for
loop, the JIT might try to instantiate it statically before the for
loop begins, so it doesn't have to include code inside the for
loop to check whether it's been instantiated during each iteration. Likewise, it's possible for a static method to be called without actually initializing any of the static properties, if the method doesn't touch any of those properties.
But if you include an explicit static constructor, it sets beforefieldinit
to false
, meaning the JIT-compiled code will wait until that point in the for
loop where the class gets accessed before instantiating the class, and it will instantiate it at that point, regardless of whether the code actually touches any of the static fields.
So the short answer is, yes, it could have an impact on the order in which your code gets run, but it's pretty rare for it to cause problems, and I don't know why it would make a difference in this particular case.
See Jon Skeet's answer for more details.
精彩评论