загрузить статические поля в классе - PullRequest
0 голосов
/ 27 октября 2019


У меня есть класс с некоторыми статическими полями. Когда они инициализируются, они добавляют себя в словарь.
Когда программа запускается во второй раз, она пытается получить доступ к содержимому словаря, но так как я не обращался ни к каким полям в классе (словарь находится в другом), онине может быть найден.

Я уже понимаю, что статические поля инициализируются, когда я обращаюсь к одному из них, но есть ли другие способы инициализировать их без вызова каких-либо методов или полей без какой-либо другой причины, кроме их инициализации один раз?


----------------------
Вот код:

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];
    }
}

Когда я использую InventoryItem.GetFromID(int id) перед доступом к чему-либо из класса Resource, словарь пуст и ничего не может быть найдено. Если я получу доступ к какому-либо ресурсу прежде, чем они появятся в Словаре.

Ответы [ 3 ]

1 голос
/ 27 октября 2019

Поскольку статические поля в классе инициализируются только при первом использовании этого класса, вы должны каким-то образом форсировать эту инициализацию, например, вызывая любой статический метод в Resource.

Пример:

в Resource добавьте

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

и где-нибудь еще в вашем проекте

Resource.Initialize();
0 голосов
/ 27 октября 2019

Статические поля и свойства инициализируются в конструкторе типов независимо от того, как вы их пишете, поэтому оба значения:

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

и

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

- это одно и то же,Разница заключается в порядке инициализации, также это позволит вам вызывать статические функции, но в случае с OP это действительно не имеет значения, поэтому ответ pamcevoy не сработает.

Клаус предоставляет правильный способделать вещи, и это будет работать, просто вам нужно будет вызвать метод Initialize перед вашим GetFromID, по крайней мере, один раз, чтобы инициализировать все статические свойства класса Resource, например:

Resource.Initialize();

InventoryItem.GetFromID(id);

Ваш последний вариант - сделать затенение метода, в основном добавьте к вашему классу Resource тот же метод GetFromID с оператором new, а затем вызовите GetFromID через класс Resource, например,

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

Но знайте, что затенение метода не то же самое, что переопределение метода, поэтому, если вы вызовете InventoryItem.GetFromID, вы не будете вызывать Resource.GetFromID. Это исключит необходимость вызова при запуске отдельного Initialize метода в классе Resource, но заставит вас хотя бы один раз вызвать GetFromID через Resource класс.

Обновление: в конце дня единственный способ инициализировать статические поля / реквизиты - получить доступ к тому или иному предмету в указанном классе.

0 голосов
/ 27 октября 2019

В качестве альтернативы вы можете инициализировать их в статическом конструкторе. Это как конструктор по умолчанию, за исключением того, что он статический. Это похоже на 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...
    }
}

в Java. Я на самом деле не пробовал, но думаю, что это сработает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...