【问题标题】:Why are my static objects not being instantiated when first access to the static class is a static method on the base class?当第一次访问静态类是基类上的静态方法时,为什么我的静态对象没有被实例化?
【发布时间】:2011-03-27 20:02:39
【问题描述】:

我有以下课程:

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

我遇到的问题是ChangeoverWithdrawalInstallation 在第一次使用静态类时是通过基类中的Resolve 方法创建的。 IE。如果我打电话给Resolve,那么Cache 将是空的。

但是,如果我在Application_Start 中执行DocketType foo = DocketType.Changeover; 之类的操作,则会创建所有静态字段,然后Cache 具有所有三个值。

创建这些静态字段的正确方法是什么?

【问题讨论】:

    标签: c# c#-4.0 static-methods static-classes


    【解决方案1】:

    我不认为DocketType 中的字段应该在您访问的所有内容都是Enumeration&lt;&gt; 时进行初始化。当您调用Enumeration&lt;&gt;.Resolve() 时,您根本没有引用DocketType 类型。每次访问静态方法或静态字段时,CLR 是否真的应该初始化所有子类?它会减慢您的代码速度,而且在大多数情况下是不必要的。

    你可以尝试写Docket.Resolve(),C#允许你这样做,但我不知道这是否会编译成与以前不同的东西;编译器可能会将其转换为 Enumeration&lt;DocketType, int, string&gt;.Resolve(),然后您又会回到原来的位置。

    说实话,我倾向于认为您的代码结构存在缺陷,而您遇到的问题就是其中的一个症状。您不必依赖 Cache 包含某些内容。当您不使用该类型时,您不必依赖某些静态类型初始化。

    因此,您的选择是:

    • 在您的 Main() 方法中的某处对 DocketType 进行毫无意义的引用,以确保初始化发生,并接受您的代码结构可能存在缺陷的想法。
    • 将静态字段移动到另一种类型,可能是 Enumeration&lt;&gt; 本身,这样可以缓解缺陷,但并不能完全解决它。
    • 考虑一下代码的基本结构并重新设计它,这样您就不必依赖正在填充的缓存。

    【讨论】:

    • 只是回复您的第一段,CLR 初始化用作类型参数的类型是合理的。即使是这样,保证这一点也是合理的。它只是没有发生:(
    • 是的,我从不喜欢这个设计:stackoverflow.com/questions/3377597/…。我只是这样做是因为我想不出替代方案。
    • 糟糕,忘记了 +1。谢谢你证实了我的恐惧。回到绘图板!
    【解决方案2】:

    编辑:我没有意识到你只是 曾经提到基本类型。这肯定有问题——在这种情况下,不能保证为DocketType 运行类型初始化程序。我以为你在调用 DocketType 中的一个方法,然后使用缓存。

    在这种情况下,它以前也不会起作用。据我所知,使用类型作为泛型类型参数不会强制进行类型初始化,这就是您所追求的。

    我认为你很难让它发挥作用。基本上你想激发类型初始化,我不知道这样做的好方法。您可以使用反射调用类型初始化程序,但您必须非常小心,只执行一次。

    我同意 Timwi 的观点:我认为你最好的解决方案是重组你的设计,这样你就不需要这个了。

    【讨论】:

    • 你又赢了,乔恩。 :) @GenericTypeTea,完整的解释见msmvps.com/blogs/jon_skeet/archive/2010/01/26/…
    • 似乎不起作用!只是要阅读那篇文章,看看我错过了什么。如果我添加static Enumeration() {},那么它会触发,但static DocketType() {} 不会。
    • 投反对票,因为这个答案是错误的(它没有解决问题)。
    • 人们非常热衷于对你投反对票,斯基特先生。我在写的时候就知道这是一种代码味道:stackoverflow.com/questions/3377597/…。为协助 +1。
    • @GenericTypeTea:考虑到我基本上误解了这个问题,对预编辑版本投反对票是合理的。我希望人们会撤消反对票,但我不确定“是的,这很糟糕”是否值得支持;)但是,是的,这是一种代码味道,我认为你会发现很难使用当前的设计.我会考虑的……
    猜你喜欢
    • 1970-01-01
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 2017-09-18
    相关资源
    最近更新 更多