0


I have a class with some static filds. When they are initialised they add themself to a Dictionary.
When the program starts a second time it tries to access the content of the Dictionary but since I haven't accessed any filds in the class (the Dictionary is in another) they can't be found.

I already understand that the static fields are initialised when I access one of them but are there any other ways to initialise them without calling any methods or fields for no other reason then nitialising them once?


----------------------
Here some code:

Resource.cs

public class Resource : InventoryItem
{
    public const int IDBase = 1000000;

    private Resource(int id) : base(IDBase + id) { }

    public static Resource Hydrogen { get; } = new Resource(1); // H
    public static Resource Helium { get; } = new Resource(2); // He
    public static Resource Lithium { get; } = new Resource(3); // Li
    public static Resource Beryllium { get; } = new Resource(4); // Be
    public static Resource Boron { get; } = new Resource(5); // B
    public static Resource Carbon { get; } = new Resource(6); // C
    public static Resource Nitrogen { get; } = new Resource(7); // N
    public static Resource Oxygen { get; } = new Resource(8); // O
    // and all the other elements....
    }
}

InventoryItem.cs

public abstract class InventoryItem
{
    public int ID { get; }

    private static readonly Dictionary<int, InventoryItem> idList = new Dictionary<int, InventoryItem>();

    public InventoryItem(int id)
    {
        ID = id;
        idList[id] = this;
    }

    public static InventoryItem GetFromID(int id)
    {
        return idList[id];
    }
}

When I use InventoryItem.GetFromID(int id) before accessing anything from the Resource class the dictionary is empty and nothing can be found. If I access any resource before they are in the Dictionary.

3 Answers 3

1

As the static fields in a class are only initialized when you first use that class, you have to somehow force this initialization, e.g. by calling any static method in Resource.

Example:

in Resource, add

public static void Initialize()
{
    // can be left empty; just forces the static fields to be initialized
}

and somewhere else in your project

Resource.Initialize();
Sign up to request clarification or add additional context in comments.

1 Comment

So I think that's mostly what I have now, I have a method Load(InventoryItem i); (without content) where I give one of each types which inherited from InvenroryItem. So on startup i can Load(a resource), Load(a weapon)... I think thats the easiest way since I only need to write this method once. Or is it possible to write the Initialize method in InventoryItem and call them in resource to load it without the need to override or shadow ot in the Resource (and all other) classes?
0

Alternatively you could initialize them in a static constructor. It's like a default constructor except it is static. It is similar to Java's static { ... } block

public class Resource : InventoryItem
{
    public const int IDBase = 1000000;

    public static Resource Hydrogen { get; }
    public static Resource Helium { get; }
    public static Resource Lithium { get; }
    // ...

    private Resource(int id) : base(IDBase + id)
    {
    }

    private static Resource()
    {
        Hydrogen = new Resource(1);
        Helium = new Resource(2);
        Lithium = new Resource(3);
        // etc...
    }
}

Caveat - I haven't actually tried this but I think it's likely to work.

6 Comments

Nope doens't work too. But thank you for your idea.
You aren't actually changing anything, you still need to access something in the Resource class to call the type constructor.
So why should I add this into a static constructor if I don't need it? This means rewriting 118 fields for no reason...
@BDevGW The thing is, in your case it doesn't make a difference, but if you had a static Dictionary field and one of the other fields does something to the Dictionary then a static constructor is useful as it allows you to change the object initialization order, also, have a look at my answer I provided another way of doing things
So you mean that I should add a static constructor so all types can load each other if needed?
|
0

Static fields and properties are initialized in a type constructor, regardless of how you write it, so both:

static Resource()
{
    Hydrogen = new Resource(1);
}

and

Hydrogen { get; } = new Resource(1);

Are the same thing, the only difference is the initialization order, also it would allow you to call static fuctions, but in OP's case it really doesn't make a difference, that's why pamcevoy's answer won't work.

Klaus provides a valid way of doing things, and it will work, just you would need to call the Initialize method before your GetFromID, at least once, as to initialize all of the Resource class's static properties, e.g.:

Resource.Initialize();

InventoryItem.GetFromID(id);

Your last option is to do method shadowing, basically add to your Resource class the same GetFromID method with the new operator and then call GetFromID through the Resource class, e.g.

public class Resource : InventoryItem
{
    public static new InventoryItem GetFromID(int id)
    {
        return InventoryItem.GetFromID(id);
    }   
}

But know that method shadowing isn't the same as overriding a method, so if you call InventoryItem.GetFromID you won't be calling Resource.GetFromID. This will eliminate the need for calling at startup a separate Initialize method in the Resource class but, it will force you to, at least once, call GetFromID through the Resource class.

Update: At the end of the day, the only way to initialize static fields/props is by accessing one thing or another in said class.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.