当第一次访问静态类是基类上的静态方法时,为什么我的静态对象没有被实例化?
我有以下类:
public class DocketType : Enumeration<DocketType, int, string>
{
public static DocketType ChangeOver = new DocketType(1, "Changeover");
public static DocketType Withdrawal = new DocketType(2, "Withdrawal");
public static DocketType Installation = new DocketType(3, "Installation");
private DocketType(int docketTypeId, string description)
: base(docketTypeId, description)
{
}
}
使用以下基类:
public abstract class Enumeration<TEnum, X, Y> : IComparable
where TEnum : Enumeration<TEnum, X, Y>
where X : IComparable
where Y : IComparable
{
protected Enumeration(X value, Y displayName)
{
AddToStaticCache(this);
}
public static TEnum Resolve(X value)
{
return Cache[value] as TEnum;
}
}
我遇到的问题是,当第一次使用静态类是通过基类中的 Resolve
方法。即,如果我调用Resolve
,则Cache
将为空。
但是,如果我在 Application_Start
中执行类似 DocketType foo = DocketType.Changeover;
的操作,则会创建所有静态字段,然后 Cache
所有三个值。
创建这些静态字段以便此场景有效的正确方法是什么?
I have the following class:
public class DocketType : Enumeration<DocketType, int, string>
{
public static DocketType ChangeOver = new DocketType(1, "Changeover");
public static DocketType Withdrawal = new DocketType(2, "Withdrawal");
public static DocketType Installation = new DocketType(3, "Installation");
private DocketType(int docketTypeId, string description)
: base(docketTypeId, description)
{
}
}
With the following base class:
public abstract class Enumeration<TEnum, X, Y> : IComparable
where TEnum : Enumeration<TEnum, X, Y>
where X : IComparable
where Y : IComparable
{
protected Enumeration(X value, Y displayName)
{
AddToStaticCache(this);
}
public static TEnum Resolve(X value)
{
return Cache[value] as TEnum;
}
}
The problem I have is that Changeover
, Withdrawal
and Installation
are not being created when the first time that the static class is used is via the Resolve
method in the base class. I.e. if I call Resolve
, then Cache
will be empty.
However, if I do something like DocketType foo = DocketType.Changeover;
in Application_Start
, then all of the static fields get created and then Cache
has all three values.
What's the correct way to create these static fields so this scenario works?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为当您访问的只是
Enumeration
时,DocketType
中的字段不应该被初始化。当您调用Enumeration>>.Resolve()
时,您根本没有引用DocketType
类型。每次访问静态方法或静态字段时,CLR 真的应该初始化所有子类吗?它会减慢你的代码速度,而且在大多数情况下是不必要的。您可以尝试编写
Docket.Resolve()
,C# 允许您这样做,但我不知道这是否会编译成与以前不同的东西;编译器可能只是将其转换为Enumeration.Resolve()
,然后您就回到了平方。老实说,我倾向于认为您的代码结构存在缺陷,而您遇到的问题就是这种缺陷的症状。您不必依赖包含某些内容的
Cache
。当您不使用该类型时,您不必依赖于某些静态类型初始化。因此,您的选择是:
Main()
方法中的某处放置对DocketType
的毫无意义的引用,以确保初始化发生,并接受您的代码结构可能是这样的想法:有缺陷的。Enumeration<>
本身,这可以减轻该缺陷,但并不能完全解决它。I don’t think the fields in
DocketType
should be initialised when all you’re accessing isEnumeration<>
. You are not referencing theDocketType
type at all when you callEnumeration<>.Resolve()
. Should the CLR really initialise all subclasses every time you access a static method or static field? It would slow down your code, and in most cases unnecessarily so.You could try writing
Docket.Resolve()
, which C# allows you to do, but I don’t know whether this will compile into something different than before; the compiler might just turn it intoEnumeration<DocketType, int, string>.Resolve()
and you’re back to sqaure one.To be honest, I am inclined to suggest that your code structure is flawed, and the problem you’re running into is a symptom of that. You shouldn’t have to rely on
Cache
containing something. You shouldn’t have to rely on some static type initialisation to have occurred when you’re not using that type.Therefore, your options are:
DocketType
somewhere in yourMain()
method to ensure the initialisation happens, and live with the idea that your code structure may be flawed.Enumeration<>
itself, which alleviates the flaw but doesn’t completely solve it.编辑:我没有意识到您仅曾经提到过基本类型。这肯定有问题 - 在这种情况下,无法保证运行 DocketType 的类型初始值设定项。我以为您正在调用 DocketType 中的方法,然后该方法使用了缓存。
在这种情况下,以前的方法也行不通。据我所知,使用类型作为泛型类型参数不会强制类型初始化,而这正是您所追求的。
我想你会很难让它发挥作用。基本上你想引发类型初始化,但我不知道这样做的好方法。您可以使用反射调用类型初始值设定项,但必须非常小心,只能执行一次。
我同意 Timwi 的观点:我认为最好的解决方案是重组你的设计,这样你就不需要这个了。
EDIT: I didn't realise that you were only ever referring to the base type. That definitely has problems - nothing is guaranteed to run the type initializer for
DocketType
in that case. I thought you were calling a method inDocketType
which then used the cache.In this case, it wouldn't have worked before, either. Using a type as a generic type argument doesn't force type initialization as far as I'm aware, and that's what you're after.
I think you'll have a hard time getting this to work. Basically you want to provoke type initialization, and I don't know a good way of doing that. You can call the type initializer with reflection, but you'd have to be very careful to only do that once.
I agree with Timwi: I think your best solution would be to restructure your design so you don't need this.