我有两个类,我试图用来实现字符串枚举模式。问题是当调用父类的操作符时,不会调用子类的静态构造函数。有没有一种方法可以解决这个问题,而无需在代码中添加黑客来初始化静态成员?
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"
之类的操作时,它失败了,因为静态构造函数还没有被解雇。我觉得应该开火,因为我使用静态操作符。
答案 0 :(得分:4)
满足以下条件之一时,将调用某个类的静态构造函数:
由于您没有创建UseTimeStringEnum的实例,因此不会在代码中访问它的静态字段,因此不会调用静态构造函数。
所以关键是:BaseStringEnum在编译时不知道UseTimeStringEnum。
我看到唯一合适的解决方案 - 我们可以在运行时引用UseTimeStringEnum。
我将静态构造函数添加到加载的BaseStringEnum类中,并使用Reflection观察所有可用的子类。
现在调用静态构造函数。
编辑:Mykroft指出有一种方法可以直接调用静态构造函数,而不是使用反射引用静态字段。所以我相信最终的代码片段应该是
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);
}
答案 1 :(得分:1)
正如其他人正确地指出我的构造函数没有被调用,因为父类不知道子类。幸运的是在this问题中我发现了一段代码片段,它们明确地调用了构造函数。
typeof(T).TypeInitializer.Invoke(null, null);
这适用于我的目的。