派生类的静态字段在基类中需要之前未初始化
本文关键字:初始化 基类 静态 字段 派生 | 更新日期: 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');
}