【问题标题】:How do I explicitly run the static constructor of an unknown type? [duplicate]如何显式运行未知类型的静态构造函数? [复制]
【发布时间】:2011-05-28 05:56:14
【问题描述】:

可能重复:
How do I invoke a static constructor with reflection?

我在各种类的静态构造函数中有一些初始化代码。我无法创建实例,也无法提前知道类型。我想确保已加载类。

我试过了:

fooType.TypeInitializer.Invoke (new object[0]);

但是得到了 MemberAccessException:类型初始化程序不可调用。

我假设这是因为 cctor 是私有的?有没有办法在不改变架构的情况下解决这个问题?

编辑:我找到了一种使用 RuntimeHelpers.RunClassConstructor 的解决方法,但这种方法似乎在 MSDN 中几乎没有记录,我不确定它是黑客还是合理的产品系统。

【问题讨论】:

  • 不是骗人的:这个问题也是关于异常以及如何避免它,以及使用RunClassConstructor的合理性。
  • @mafuctr:您是否尝试过fooType.TypeInitializer.Invoke(null, null);,正如那个答案中提到的那样?
  • 为什么框架对你的类的静态构造函数的自动调用对你不起作用?
  • @Ani:这确实有效,但我对此有一些疑问......

标签: c# .net static-constructor typeinitializer


【解决方案1】:

编辑:显然不会按原样工作,因为海报状态无法提前知道类型。离开这里可能有助于为未来的读者澄清......

如果我正确理解了您的需求——在类似情况下,我会创建一个引用静态类的包装器,但它仍然是测试套件的一部分。然后,您可以实例化包装器并按需初始化静态。这意味着您可以保持架构不变,并将包装器作为测试框架的一部分。

公共静态类 MyStatic { 公共静态字符串 SomeToolMethod() { 返回“你好”; } } public class MyStaticWrapper // 或代理,技术上? { 公共静态字符串 SomeToolMethod() { 返回 MyStatic.SomeToolMethod(); } } fooType.TypeInitializer.Invoke(new MyStaticWrapper()); /// 未经测试,这里的语法不确定

【讨论】:

  • 我不太明白,你能补充一个简短的例子吗?
  • 恐怕这会失败,因为我需要提前知道所有类型,这样我才能在包装类中调用它们的静态方法。
  • 好的,干杯,将留在这里作为答案,以防它帮助未来的读者,已添加警告作为标题...
【解决方案2】:

我不确定为什么会这样,但据我所知(在Skeet 的帮助下)如果我有一个静态类

public static class Statics1
{
    public static string Value1 { get; set; }

    static Statics1()
    {
        Console.WriteLine("Statics1 cctor");
        Value1 = "Initialized 1";
    }
}

代码:

Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null);
or
staticType.TypeInitializer.Invoke(new object[0]);

会抛出异常,因为这会以某种方式解析为 .ctor,而不是类的 .cctor。
如果我使用显式静态类,则将其视为抽象密封类,因此例外是无法实例化抽象类,而如果我使用带有静态构造函数的常规类,则例外是类型初始化器不是可调用。

但是如果我使用带有两个参数(实例、参数)的 Invoke 重载,像这样:

Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null, null);

明确说明我正在调用一个静态方法(这是第一个 null 的含义 - 没有实例 == 静态),这可以正常工作并初始化类。


也就是说,静态构造函数是奇怪的野兽。以这种方式调用一个将调用静态构造函数,即使它已经被执行,即这个代码:

Console.WriteLine(Statics1.Value1);

Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null, null);

将调用静态构造函数两次。因此,如果您的 cctor 具有潜在的重要副作用,例如创建文件、打开数据库等,您可能需要重新考虑这种方法。

此外,尽管出于可读性的原因我更喜欢静态构造函数,但从性能的角度来看,字段初始值设定项比静态构造函数有点 faster

【讨论】:

  • 太棒了!这回答了我在 Ani 对 OP 发表评论后要问的大部分问题。
  • 关于后半部分(两次调用),有没有办法避免呢?那么stackoverflow.com/questions/2658561/… 呢……你能把这个作为答案添加到那里吗,因为它看起来对于 Invoke(null) 和 Invoke(null, null) 的行为有很大不同?
  • 实际上,我建议使用RuntimeHelpers.RunClassConstructor,即使它更底层并且可能依赖于版本。
猜你喜欢
  • 2012-03-09
  • 1970-01-01
  • 2022-07-07
  • 2012-07-16
  • 2011-07-15
  • 1970-01-01
  • 2010-11-28
  • 2012-07-13
相关资源
最近更新 更多