【问题标题】:How to initialize a C# static class before it is actually needed?如何在实际需要之前初始化 C# 静态类?
【发布时间】:2012-01-05 19:25:37
【问题描述】:

我有一个带有静态构造函数的静态类,它需要一些时间(10-15 秒)来执行和完全初始化该类。为了提高性能,我决定让这个静态类显式初始化,而不是在第一次需要时初始化,以便在实际需要使用时准备好使用。

我的第一个想法是为该类创建一个Initialize() 方法,但由于我已经有一个静态构造函数,所以这个方法似乎不需要做任何事情,除了作为显式初始化类的调用方法无需访问其任何其他公共方法或属性。有一个不直接做任何事情的方法对我来说似乎不合适。

然后我想我可以将代码从静态构造函数移动到这个 Initialize() 方法中,但我也希望在第一次需要时初始化该类并且 Initialize() 方法没有被显式调用.

总而言之,我希望遵守以下标准:

  • 我希望允许显式初始化静态类(可能通过使用公共Initialize() 方法)。
  • 我不想在不需要时访问类上的任何其他公共方法或属性,即使这会初始化静态类。
  • 如果类没有被显式初始化,我仍然想在第一次需要它时初始化它(即,当访问其他公共方法或属性以使用它们提供的功能或数据时)。
  • 这是一个辅助类,我不需要使用单例设计模式。

对于用 C# 编写的静态类,遵守上述标准的正确方法是什么?这也适用于其他编程语言(例如 Java),但我个人对用 C# 编写的解决方案感兴趣。

【问题讨论】:

  • 为什么不在静态构造函数中初始化类呢?我发现您不需要手动初始化。
  • 不是“可初始化”的静态类不是静态类吗?这种行为的目的是什么?您似乎想根据静态值实例化一个类。
  • @Jeremy Holovacs:初始化静态类是指初始化它的所有静态成员。该类用作辅助类,我不需要维护它的实际实例。
  • @Ramhound,请指点我如何制作一个空静态类...在我看来,这在术语上是矛盾的。

标签: c# static


【解决方案1】:

我会使用初始化方法(编辑:请参阅 Jon 的回答)。但如果你真的只想使用构造函数,你可以这样做:

var type = typeof (YourType);
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);

RunClassConstructor 允许您强制类构造函数(静态构造函数)在尚未运行的情况下运行。如果它已经运行,比如说因为你使用了类的静态成员,那么这没有任何效果。再次运行它没有任何效果。

【讨论】:

  • 有趣的方法。这不是我想要使用的,但很高兴知道它是一个选项。
【解决方案2】:

我可能会选择 Initialize 方法 - 它可以做一些有用的事情:

  • 它可以记录您正在显式尝试初始化类,并带有堆栈跟踪
  • 如果类已经通过另一个Initialize调用初始化,它可能会抛出异常
  • 您可以可能(通过一些努力和重新组织)对事物进行排序,以便在初始化期间引起的任何异常都在没有您通常会得到的TypeInitializationException 的情况下传播。

【讨论】:

  • 如何判断静态类是否已经初始化?我没有使用单例模式,所以我没有要引用的类的实例。静态构造函数总是在Initialize() 方法体之前调用,所以静态成员总是被初始化。如果不使用 Singleton 模式,我不知道如何做到这一点。
  • @Bernard:你会保留一个静态变量来说明是否首先调用了 Initialize。请注意“通过另一个 Initialize”调用部分 - 只有 Initialize 会设置该值,但静态构造函数会测试它是否已设置。
【解决方案3】:

两种解决方法:

  1. 将构造函数代码移至Initialize(),以便您可以显式调用。并将构造函数中的代码替换为只调用Initialize() 方法,以防静态类在您显式调用之前动态加载

    public static class StaticClass
    {
        // actual constructor
        static StaticClass()
        {
            Initialize();
        }
    
        // explicit "constructor"
        public static void Initialize()
        {
            MyProperty = "Some Value";
        }
    
        public static string MyProperty { get; set; }
    
    }
    

    如果你愿意,然后像这样初始化:

    StaticClass.Initialize();
    

    或者在第一次使用的时候动态初始化

  2. 在语义上不那么原始,但您可以通过使用属性并将其放入临时变量中来触发静态类的有机初始化。

    那么就这样做吧:

    // trigger static initilaization
    var dummy = StaticClass.MyProperty;
    

    仍然允许您在需要时调用它,但如果在初始化时有一些性能成本,您可以尝试在启动时调用它,而不是在用户第一次执行触发该代码的操作时调用它。

有关静态初始化的另一个有用概述,请参阅:Is the order of static class initialization in C# deterministic?

【讨论】:

    【解决方案4】:

    我不确定您是否可以指定何时加载静态构造函数。

    来自 MSDN “在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。”

    http://msdn.microsoft.com/en-us/library/k9x6w0hc(v=vs.80).aspx

    *编辑:* 在这里添加单例模式会有帮助吗? getter 可以通过检查类中的标志 IsLoaded=true 来调用 Initialize()。后续调用不会调用 Initialize()

    【讨论】:

    • 我意识到不能显式调用静态构造函数,但我想允许类的机制说:“是的,我希望现在初始化这个类!”同时仍然允许,“我还没有初始化你,但请在我开始使用你之前初始化你自己。”
    • 使用单例模式将强制使用Initialize() 方法,因为您需要显式创建类的单个实例。我只是觉得我不需要维护此类的实例,因为我将此类用作辅助类,并且不需要将它的实例作为参数传递给其他类方法。
    【解决方案5】:

    这种方法对我来说似乎并不讨厌。我可以将方法命名为 Touch(),给它一个空的主体,并添加适当的注释。这是否足以让您摆脱对此感觉不对劲的感觉?

    【讨论】:

    • 并非如此。我从没想过我会用Touch() 方法设计一个类。感觉很脏。 :)
    • 我想知道输入var type = typeof(ClassToInitialize); 是否足够,虽然我不知道它是否会被编译掉。
    猜你喜欢
    • 1970-01-01
    • 2016-12-30
    • 2017-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-09
    相关资源
    最近更新 更多