派生类的静态字段在基类中需要之前未初始化

本文关键字:初始化 基类 静态 字段 派生 | 更新日期: 2023-09-27 18:33:58

我正在尝试创建一个基类,可以从中派生出可能具有多个字段和方法的自定义枚举类。基类为每个枚举类型保留所有已定义值的列表,并为所有值保留一个名称变量。我遇到的问题是,由于 CLR 的行为,派生类的静态字段在我直接调用其中一个之前不会初始化,但需要初始化它们才能将自己添加到该枚举类型的已定义值列表中。

例如,集合 Day.Values 将为空,除非我之前执行以下操作:

今天的日子 = 天.星期一;

有没有办法确保如果我调用 Day.Values 时将初始化 Day 中的静态字段,即使我不先调用其中一个字段?或者,有没有更好的方法来实现此功能?

public abstract class EnumBase<T> where T : EnumBase<T>
{
    private static List<T> values = new List<T>();
    public static ReadOnlyCollection<T> Values
    {
        get
        {
            return values.AsReadOnly();
        }
    }
    public string name { get; private set; }
    protected EnumBase(string name)
    {
        this.name = name;
        values.Add((T)this);
    }
    public override string ToString()
    {
        return this.name;
    }
}
public class Day : EnumBase<Day>
{
    public static readonly Day MONDAY = new Day("monday");
    public static readonly Day TUESDAY = new Day("tuesday");
    //...
    private Day (string name) : base (name) 
    {
    }
}

派生类的静态字段在基类中需要之前未初始化

可以使用反射来检查相关字段的派生类型来解决此问题。

此外,您可以在首次访问Values时执行此初始化,将这项工作推迟到需要并缓存结果。

下面是一个示例:

public abstract class EnumBase<T> where T : EnumBase<T>
{
    static Lazy<List<T>> values = new Lazy<List<T>>(FindEnumMembers);
    public static IEnumerable<T> Values
    {
        get
        {
            return values.Value;
        }
    }
    static List<T> FindEnumMembers()
    {
        Type derivedType = typeof(T);
        return derivedType.GetFields()
                          .Where(f => f.FieldType == derivedType)
                          .Select(f => (T)f.GetValue(null))
                          .ToList();
    }
    public string name { get; private set; }
    protected EnumBase(string name)
    {
        this.name = name;
    }
    public override string ToString()
    {
        return this.name;
    }
}
public class Day : EnumBase<Day>
{
    public static readonly Day MONDAY = new Day("monday");
    public static readonly Day TUESDAY = new Day("tuesday");
    //...
    private Day (string name) : base (name) 
    {
    }
}

访问应该以任何一种方式工作,因为这些是同义词:

Day.Values
//or//
EnumBase<Day>.Values

再次请注意,这些是同义词,因为这是原始问题的根本原因。 调用Day.Values实际上被解释为EnumBase<Day>.Values,因此另一种类型的静态成员Day不会被此调用初始化。通过在 EnumBase<T> 中使用反射并请求派生类型的字段,它们将被初始化(如果尚未初始化),作为调用GetValue的副作用,就像您在那时静态访问它们一样。

我没有

时间对此进行测试,但这里有一个将每个枚举类作为单例的示例。(我希望它有效...:D

我从基类中取出静态并将其添加到"Day"单例中,以便类的不同扩展不会意外共享数据。

可以从任何地方调用单例并创建自身的一个实例。

Day.method(); // From anywhere

Day.addEnum('星期三');

public abstract class EnumBase<T> where T : EnumBase<T>
{
    private List<T> values = new List<T>();
    public ReadOnlyCollection<T> Values
    {
        get
        {
            return values.AsReadOnly();
        }
    }
    public string name { get; private set; }
    protected EnumBase()
    {
    }
    public string addEnum()
    {
        this.name = name;
        values.Add((T)this);
    }
    public override string ToString()
    {
        return this.name;
    }
}
using System;
public class Day : EnumBase<Day>
{
    private static Day instance;
    private Day() {}
    public static Day Instance
    {
        get 
        {
            if (instance == null)
            {
                instance = new Day();
            }
            return instance;
        }
    }
    addEnum('monday');
    addEnum('tuesday');
}