release mode static initialization error

R

roger

Here's a weird one...

The code below works just fine when I build in DEBUG mode.
Today, I tried to build my solution in RELEASE mode, and
immediately fell over this problem - apparently something
in the order or sequencing or something regarding static
initialization.

Consider this class, which implements a singleton pattern:


public class DataCache {


private DataCache(int flag) {
Console.WriteLine("DataCache ctor " + flag);
}


public static DataCache Instance {
get {
#if true
bool b = instance == null;
return b ? (instance = new DataCache(1)) : instance;
#else
return instance;
#endif
}
}


private static DataCache instance = new DataCache(0);

}

- With the #if true code disabled, I get the following error

Unhandled Exception: System.TypeInitializationException:
The type initializer for "DataCache" threw an exception. --->
System.NullReference
Exception: Object reference not set to an instance of an object.
at DataCache..ctor(Int32 flag)
at DataCache..cctor()
--- End of inner exception stack trace ---
at DataCache.get_Instance()
at Server.Main(String[] args)



- With the #if true code enabled, I never see the DataCache
ctor being called with flag==1. I still see it called with
flag value as 0.
This tells me that in the Instance method, b was false, meaning
that the instance member was not null.



Of course, I was not able to reproduce this problem in a simple
test case. Maybe there's something about the rest of the setup
that I have (difficult to explain/post) so I thought that I'd first
check and see if this sounds familiar to anybody.

Again, to stress the point that I see nothing like this when
compiling in DEBUG mode. The private static instance is valid
and returned as you'd expect.


Any ideas?

(using Visual Studio 2003 framework version 1.1.4322 - fwiw)

Thanks.
 
J

Jon Skeet [C# MVP]

roger said:
Here's a weird one...

The code below works just fine when I build in DEBUG mode.
Today, I tried to build my solution in RELEASE mode, and
immediately fell over this problem - apparently something
in the order or sequencing or something regarding static
initialization.

Consider this class, which implements a singleton pattern:

It sounds like you're probably running into beforefieldinit problems.

See http://www.pobox.com/~skeet/csharp/beforefieldinit.html
and
http://www.pobox.com/~skeet/csharp/singleton.html

Did you really get the exception with the code you gave, rather than
*slightly* different code? I can't see how the constructor would throw
a NullReferenceException anyway...
 
R

roger


Indeed. The use of a static constructor

static DataCache() { instance = new DataCache(); }

as opposed to declaring

private static instance = new DataCache();

has apparently solved the problem.

The thing that is disturbing to me is the difference in
behavior between DEBUG and RELEASE configurations.

Seems like if it's wrong, it should be wrong in both modes.

Or am I just being naive?
 
J

Jon Skeet [C# MVP]

roger said:
Indeed. The use of a static constructor

static DataCache() { instance = new DataCache(); }

as opposed to declaring

private static instance = new DataCache();

has apparently solved the problem.
Good.

The thing that is disturbing to me is the difference in
behavior between DEBUG and RELEASE configurations.

That doesn't disturb me *too* much - basically the JIT doesn't make as
many optimisations when it's running in the debugger. (I suspect if you
ran the debug code outside the debugger, you'd see the same as with the
release code.)
Seems like if it's wrong, it should be wrong in both modes.

Or am I just being naive?

While I can see how that would be desirable, it would have unpleasant
side effects - people would be confused when stepping through code to
find the type initialiser run at the start of a method rather than when
the type is first used, for instance. Maybe it would be better to
educate people than to hide that from them though...
 
R

roger

That doesn't disturb me *too* much - basically the JIT doesn't make as
many optimisations when it's running in the debugger. (I suspect if you
ran the debug code outside the debugger, you'd see the same as with the
release code.)

No. I run the debug release outside the debugger all the time.
Never saw it.
While I can see how that would be desirable, it would have unpleasant
side effects - people would be confused when stepping through code to
find the type initialiser run at the start of a method rather than when
the type is first used, for instance. Maybe it would be better to
educate people than to hide that from them though...

I doubt that would be all that confusing. Certainly something
people would learn and understand.
In that regard, it would help the education process along.

And would be much less confusing than having an application that
behaves differently owing only to the change in compilation mode.
This time I was lucky - the application crashed immediately.
Much worse are the ones that don't fail outright, but just produce
subtly incorrect results that may or may not be noticed...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top