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

时间:2014-12-11 20:42:14

标签: c# static-variables

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

例如,除非我之前做过类似的事情,否则集合Day.Values将为空。

今天= Day.MONDAY;

如果我在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) 
    {

    }
}

2 个答案:

答案 0 :(得分:0)

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

我从你的基类中取出静态并将其添加到&#34; Day&#34;单身,这样不同的类扩展不会意外地共享数据。

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

Day.method(); // From anywhere

Day.addEnum(&#39;星期三&#39);

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');
}

答案 1 :(得分:0)

您可以使用反射来检查相关字段的派生类型。

此外,您可以在首次访问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的副作用就像它们将会是这样的那时他们静静地访问了他们。