【问题标题】:Why isn't my static constructor being called为什么不调用我的静态构造函数
【发布时间】:2014-09-18 02:52:29
【问题描述】:

我尝试使用两个类来实现字符串枚举模式。问题是当调用父类的运算符时,子类的静态构造函数没有被调用。有没有一种方法可以解决这个问题,而无需在代码中添加 hack 来初始化静态成员?

public abstract class BaseStringEnum<T> where T : BaseStringEnum<T>
{
    public string Value { get; private set; }

    private static List<T> _values = null;
    protected static List<T> Values 
    {
        get
        {
            if (_values == null)
            {
                _values = new List<T>();
            }

            return _values;
        }
    }

    protected BaseStringEnum(string value, string resId)
    {
        Value = value;
        ResourceId = resId;

        Values.Add((T)this);
    }

    public static implicit operator string(BaseStringEnum<T> value)
    {
        return value.Value;
    }

    public static implicit operator BaseStringEnum<T>(string value)
    {
        return Values.Where(v => v.Value.Trim() == value.Trim()).First();
    }
}


public sealed class UseTimeStringEnum : BaseStringEnum<UseTimeStringEnum>
{
    private UseTimeStringEnum(string value, string resourceId) : base(value, resourceId) { }

    public static readonly UseTimeStringEnum None;// = new UseTimeStringEnum("N", "None");
    public static readonly UseTimeStringEnum Required;// = new UseTimeStringEnum("R", "Required");
    public static readonly UseTimeStringEnum Optional;// = new UseTimeStringEnum("O", "Optional");

    static UseTimeStringEnum()
    {
        None = new UseTimeStringEnum("N", "None");
        Required = new UseTimeStringEnum("R", "Required");
        Optional = new UseTimeStringEnum("O", "Optional");
    }
}

问题是当代码尝试执行(UseTimeStringEnum)"R" 之类的操作时,它会失败,因为静态构造函数尚未触发。我觉得它应该触发,因为我使用的是静态运算符。

【问题讨论】:

  • 父类不知道子类中的静态构造函数,这就是为什么引用父类时不调用构造函数的原因。即使您将类更改为结构,也不会产生影响。
  • “失败”是什么意思?
  • 我在这里只看到基类和子类。为什么这是一个关于嵌套类的问题的欺骗?
  • 另外说明;这是字符串枚举的正确方法吗?
  • @PeterRitchie 当我说“失败”时,我的意思是没有达到我的预期。在这种情况下,由于构造函数尚未触发,因此列表为空。这会导致在 First 调用上引发异常。

标签: c# .net


【解决方案1】:

当满足下列条件之一时,调用某个类的静态构造函数:

  1. 类的实例已创建;
  2. 访问类的任何静态字段。

由于您没有创建 UseTimeStringEnum 的实例,也没有访问代码中的静态字段,因此不会调用静态构造函数。

所以重点是:BaseStringEnum 在编译时不知道 UseTimeStringEnum。

我看到了唯一合适的解决方案——我们可以在运行时引用 UseTimeStringEnum。

我向 BaseStringEnum 类添加了静态构造函数,该类加载并使用反射观察所有可用的子类。

现在调用静态构造函数。

编辑:Mykroft 指出有一种方法可以直接调用静态构造函数,而不是使用反射引用静态字段。所以我相信最终的代码 sn-p 应该是

static BaseStringEnum()
{
    var StringEnumTypes = AppDomain.CurrentDomain.GetAssemblies()
          .SelectMany(a => a.GetTypes())
          .Where(type => type.IsSubclassOf(typeof(BaseStringEnum<T>)));

    foreach (var type in StringEnumTypes) type.TypeInitializer.Invoke(null, null);
}

【讨论】:

    【解决方案2】:

    正如其他人正确指出的那样,我的构造函数没有被调用,因为父类不知道子类。幸运的是,在this SO 问题中,我发现了一段显式调用构造函数的代码。

    typeof(T).TypeInitializer.Invoke(null, null); 
    

    这适用于我的目的。

    【讨论】:

      猜你喜欢
      • 2013-12-04
      • 1970-01-01
      • 2011-05-29
      • 1970-01-01
      • 1970-01-01
      • 2011-08-13
      • 2011-11-16
      • 2020-11-01
      • 2012-08-30
      相关资源
      最近更新 更多