7

可能重复:
如何使用反射调用静态构造函数?

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

我试过这个:

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

但是得到了 MemberAccessException: Type initializer was not callable。

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

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

4

2 回答 2

8

我不确定为什么会这样,但据我推测(在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 具有潜在的重要副作用,例如创建文件、打开数据库等,您可能需要重新考虑这种方法。

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

于 2010-12-20T13:19:37.290 回答
0

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

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

公共静态类 MyStatic
{
    公共静态字符串 SomeToolMethod()
    {
        返回“你好”;
    }
}

public class MyStaticWrapper // 或代理,技术上?
{
    公共静态字符串 SomeToolMethod()
    {
        返回 MyStatic.SomeToolMethod();
    }
}

fooType.TypeInitializer.Invoke(new MyStaticWrapper()); /// 未经测试,这里的语法不确定
于 2010-12-20T12:51:46.183 回答