【问题标题】:load static fields in class在类中加载静态字段
【发布时间】:2019-10-26 22:24:51
【问题描述】:


我有一堂课,里面有一些静态字段。当它们被初始化时,它们会将自己添加到字典中。
当程序第二次启动时,它会尝试访问字典的内容,但由于我没有访问类中的任何字段(字典在另一个),所以找不到它们。

我已经明白,当我访问其中一个静态字段时会初始化它们,但是是否有任何其他方法可以初始化它们而无需无缘无故调用任何方法或字段,然后将它们初始化一次?


----------
这里有一些代码:

资源.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];
    }
}

当我在从 Resource 类访问任何内容之前使用 InventoryItem.GetFromID(int id) 时,字典是空的,什么也找不到。如果我在字典中之前访问任何资源。

【问题讨论】:

    标签: c# static initialization


    【解决方案1】:

    由于类中的静态字段仅在您第一次使用该类时才被初始化,因此您必须以某种方式强制进行此初始化,例如通过调用 Resource 中的任何静态方法。

    例子:

    在资源中,添加

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

    以及项目中的其他地方

    Resource.Initialize();
    

    【讨论】:

    • 所以我认为这主要是我现在所拥有的,我有一个方法Load(InventoryItem i);(没有内容),其中我给出了从 InvenroryItem 继承的每种类型之一。所以在启动时我可以加载(资源),加载(武器)......我认为这是最简单的方法,因为我只需要编写一次这个方法。或者是否可以在 InventoryItem 中编写 Initialize 方法并在资源中调用它们来加载它,而无需在 Resource(和所有其他)类中覆盖或隐藏 ot?
    【解决方案2】:

    或者,您可以在静态构造函数中初始化它们。 它就像一个默认构造函数,只是它是静态的。 类似于Java的static { ... }

    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...
        }
    }
    

    警告 - 我实际上并没有尝试过,但我认为它可能会起作用。

    【讨论】:

    • 不也不起作用。不过谢谢你的想法。
    • 你实际上并没有改变任何东西,你仍然需要访问 Resource 类中的一些东西来调用类型构造函数。
    • 那么,如果我不需要它,为什么要将它添加到静态构造函数中呢?这意味着无缘无故重写118个字段...
    • @BDevGW 问题是,在您的情况下,它没有任何区别,但是如果您有一个静态 Dictionary 字段并且其他字段之一对 Dictionary 执行某些操作,那么静态构造函数很有用因为它允许您更改对象初始化顺序,另外,看看我的回答我提供了另一种做事方式
    • 所以你的意思是我应该添加一个静态构造函数,以便所有类型在需要时可以相互加载?
    【解决方案3】:

    静态字段和属性在类型构造函数中初始化,无论你如何编写它,所以两者都是:

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

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

    是一样的,唯一的区别是初始化顺序,它也可以让你调用静态函数,但在 OP 的情况下它真的没有什么区别,这就是为什么 pamcevoy 的答案不起作用。

    Klaus 提供了一种有效的做事方式,它会起作用,只是您需要在 GetFromID 之前调用 Initialize 方法,至少一次,以初始化所有 Resource 类的静态属性,例如:

    Resource.Initialize();
    
    InventoryItem.GetFromID(id);
    

    您的最后一个选择是进行方法阴影,基本上使用new 运算符将相同的GetFromID 方法添加到您的Resource 类,然后通过Resource 类调用GetFromID,例如

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

    但要知道方法遮蔽与覆盖方法不同,因此如果您调用InventoryItem.GetFromID,您将不会调用Resource.GetFromID。这将消除在启动时调用 Resource 类中单独的 Initialize 方法的需要,但它会强制您至少一次通过 Resource 类调用 GetFromID

    更新:归根结底,初始化静态字段/道具的唯一方法是访问所述类中的一件事或另一件事。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-26
      • 2013-09-16
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多