Structs not being initialized

Today, I figured out it might be interesting to have some sort of enumeration in C# similar to the class enums in Java (which has been done numerous times) but as immutable structs. I came up with something like this:

public struct TestStruct {

    public static readonly TestStruct Value1 = 1;
    public static readonly TestStruct Value2 = 2;
    public static readonly TestStruct Value3 = 3;

    private int _value;

    private TestStruct(int value) {
        _value = value;
    }

    public static implicit operator int(TestStruct instance) {
        return instance._value;
    }

}

The code compiles fine, however when I try to access TestStruct.Value2, a NullReferenceException occurs.

This was just a test, but now I'm wondering.. what happens to the static readonly TestStructs? Why can I assign an integer to them, although they are not being initialized?

Update

This one compiles.

public struct LogLevel
{
    // log levels
    public static readonly LogLevel Information = 0x0000;
    public static readonly LogLevel Warning = 0x0001;
    public static readonly LogLevel Error = 0x0002;
    public static readonly LogLevel Verbose = 0x0004;
    public static readonly LogLevel Debug = 0x0008;
    public static readonly LogLevel Trace = 0x0016;
    public static readonly LogLevel Critical = 0x0032;
    public static readonly LogLevel Fatal = 0x0064;


    private static readonly Dictionary<int, LogLevel> Levels
        = new Dictionary<int, LogLevel>();

    private readonly int _value;

    private LogLevel(int value)
    {
        if (Levels.ContainsKey(value))
            throw new ArgumentException("Level already defined.");

        _value = value;
        Levels.Add(value, this);
    }

    public static implicit operator LogLevel(int value)
    {
        LogLevel level;
        if (!Levels.TryGetValue(value, out level))
            throw new ArgumentOutOfRangeException("value");
        return level;
    }

    public static implicit operator int(LogLevel level)
    {
        return level._value;
    }
}

Update 2

    // extension method for log levels
    public static void Debug(this ILogger logger, string message)
    {
        logger.Write(message, LogLevel.Debug);
    }

    // method on ILogger, implementation is Log4NetLogger (wrapper)
    void Write(string message, LogLevel severity);

    // call (simple)
    Logger.Debug("Test");
Jon Skeet
people
quotationmark

There are two problems here:

  1. You're using the implicit conversion from int when you're initializing the fields... that expects the value to already be there. You should be using the constructor instead. So this:

    public static readonly LogLevel Information = 0x0000;
    

    should be

    public static readonly LogLevel Information = new LogLevel(0x0000);
    
  2. You're trying to access the dictionary before the Levels variable has been initialized. You need to move this statement:

    private static readonly Dictionary<int, LogLevel> Levels
        = new Dictionary<int, LogLevel>();
    

    ... above the field declarations. That way it's initialized before the field initializers call the constructor.

At that point, it should work. It's not necessarily a design I'd use myself, but it at least removes the issues you've got at the moment.

people

See more on this question at Stackoverflow