tags:

views:

123

answers:

3

I have the following code. Is it not the exact code which I am using since it is internal to my place of work, but is a representation of the scenario which I am encountering.

public class Service : ServiceBase
{

    private static readonly Service _instance = new Service();

    private static readonly string a = @"D:\test.txt";

    private Service () : base()
    {
        // the value stored in "a" is always blank.
        Console.Writeline(a);
    }

    static void Main(string[] args)
    {
        Run(_instance);
    }

}

This code is a windows service (there is service specific code in the base class). For some reason the value stored in "a" is always blank in the constructor. Is there something obvious which is doing this, or is it a quirk in the .NET platform?

+10  A: 

Swap round the declarations of the _instance and a fields. In C#, static fields are initialized in the order in which they're declared. In other words, your Server constructor is running too early.

Or you could declare a as const, which removes it from the construction process.

Tim Robinson
+4  A: 

The problem is that you're calling the constructor before the initializer for a is run, so you're seeing the default value for a. In fact, it's not blank (an empty string) - it's null. You can fix this by reordering:

public class Service : ServiceBase
{
    // Initialize a first
    private static readonly string a = @"D:\test.txt";

    private static readonly Service _instance = new Service();

    ...
}

The static initializers are run in the textual order (which becomes somewhat undefined with partial classes). From section 10.5.5.1 of the C# 3.0 spec:

The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration. If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.

I'm not sure I use that would though... it's too easy to break.

Can you change it to const? That would be more robust:

    private const string a = @"D:\test.txt";

That way it won't matter if someone changes the order again at a later date, thinking that reordering is a harmless operation. Presumably you were unaware of the importance of the order here, otherwise you wouldn't have asked this question - how willing are you to gamble that another programmer looking at the same code won't have the same issue? :)

Jon Skeet
Others will disagree but this is the very reason I prefer to have a static constructor. All initialization occurs there rather than something non-obvious. Performance .... blah blah blah ... One bug like this and all the perf you "gained" is gone. nuff said.
No Refunds No Returns
The performance penalty for a static constructor is tiny in most cases... it's a good option. I prefer the const here anyway, but to initialize a bunch of non-constants it's a good idea.
Jon Skeet
+1  A: 

Static fields are instantiated in the order they appear in the text file. So your Service is being constructed before the string is initialized. if you swap those two lines it should work.

Link: http://msdn.microsoft.com/en-us/library/aa645758%28VS.71%29.aspx

Oh, and the singleton pattern is often an anti-pattern. Try to avoid using it if possible.

Mark Byers
Unfortunately this is someone else's template that I have to work with ...
Nippysaurus