【问题标题】:Strange behaviour with static fields静态字段的奇怪行为
【发布时间】:2010-12-08 17:20:42
【问题描述】:

我正在尝试使自定义枚举类正常工作,它应该使我能够创建具有用户友好标识符和任意关联值的枚举。到目前为止一切顺利:

public class EnumBase<T, E>
    where E : class
{
    private static readonly List<E> list = new List<E>();

    private string text;
    private T value;

    public string Text { get { return text; } }
    public T Value { get { return value; } }

    public EnumBase(string text, T value)
    {
        this.text = text;
        this.value = value;
        list.Add(this as E);
    }

    protected static IEnumerable<E> ItemList
    {
        get { return list; }
    }
}

public class Zahlungsart : EnumBase<int, Zahlungsart>
{
    public static readonly Zahlungsart Erlagsschein = new Zahlungsart("Erlagsschein", 0);
    public static readonly Zahlungsart Lastschrift = new Zahlungsart("Lastschrift", 1);

    private Zahlungsart(string text, int value) : base(text, value) { }
    public static new IEnumerable<Zahlungsart> ItemList { get { return EnumBase<int, Zahlungsart>.ItemList; } }
}

现在我的问题是:

Console.WriteLine(Zahlungsart.ItemList.Count());

下面的语句给了我 0,而不是 2。我认为问题是由于 beforefieldinit。我可以通过直接调用特定枚举的某些方法来解决这个问题,这会强制加载静态字段,但我认为这不是最好的解决方案。

提示:请不要在这里为枚举提出某种 [UserfriendlyName()] 属性,我已经知道了。

编辑 谢谢,汉斯。我自己的代码确实有错字,调用了错误的通用专业化。

现在我的问题是,我可以摆脱在每个子类中对 ItemList 的重新定义,但似乎这是初始化静态字段所必需的。

【问题讨论】:

  • 当我运行完全相同的代码时,我得到“2”作为输出。

标签: c# .net generics static-constructor


【解决方案1】:

使用“静态构造函数”怎么样??

public class Zahlungsart : EnumBase<int, Zahlungsart>
{
    public static readonly Zahlungsart Erlagsschein;
    public static readonly Zahlungsart Lastschrift;

    static Zahlungsart()
    {
        Erlagsschein = new Zahlungsart("Erlagsschein", 0);
        Lastschrift = new Zahlungsart("Lastschrift", 1);
    }

    private Zahlungsart(string text, int value) : base(text, value) { }
    public static new IEnumerable<Zahlungsart> ItemList { get { return EnumBase<int, Zahlungsart>.ItemList; } }
}

【讨论】:

  • 编译器已经自动生成一个cctor来初始化只读成员。这没有任何区别。
  • @Hans,可以。静态构造函数将删除“beforefieldinit”标志,导致在第一次使用该类型时执行所有静态字段。没有静态构造函数的类型被标记为“beforefieldinit”,并且静态字段只保证在它们第一次被引用之前被初始化,但不能保证它们在其他代码在该类型中执行之前被初始化。 yoda.arachsys.com/csharp/beforefieldinit.html
【解决方案2】:

您的代码不会重现问题。但是,如果您像这样更改属性,您将获得重现:

    public new static IEnumerable<Zahlungsart> ItemList { 
        get { return EnumBase<uint, Zahlungsart>.ItemList; }   // Note: uint instead of int
    }

请注意,从泛型类型生成的每个具体类都有自己的静态字段,它们是不共享的。

【讨论】:

  • 该死的你是对的,我在代码上摆弄了这么多,以至于我发布了一个实际工作的代码:)
  • 我可以绕过每个子类中 ItemList 的重新定义吗?没有它,就不会调用静态 ctor。这意味着计数为 0,直到我访问相关派生类的第一个静态成员。
  • 你不能,这是基本行为。静态成员的类型不同,无法共享。您需要重新考虑这一点。
猜你喜欢
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 2011-03-14
  • 2015-01-12
  • 1970-01-01
  • 2014-03-18
  • 1970-01-01
  • 2011-12-31
相关资源
最近更新 更多