如何显式运行未知类型的静态构造函数?

发布于 2024-10-08 15:04:21 字数 563 浏览 0 评论 0原文

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

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

我尝试了这个:

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

但得到了 MemberAccessException:类型初始值设定项不可调用。

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

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

Possible Duplicate:
How do I invoke a static constructor with reflection?

I've got some initialization code in the static constructor of various classes. I can't create instances, nor do I know the types in advance. I would like to ensure the classes are loaded.

I tried this:

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

But got a MemberAccessException: Type initializer was not callable.

I'm assuming this is because the cctor is private? Is there a way to fix this without changing the architecture?

Edit: I found a workaround using RuntimeHelpers.RunClassConstructor, but this way seems to be barely documented in the MSDN and I'm not sure if it is a hack or a reasonable, prod system like way.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半世蒼涼 2024-10-15 15:04:21

我不确定为什么会这样,但据我推理(在 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 的含义 - 无实例 == static),这将起作用并初始化该类。


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

Console.WriteLine(Statics1.Value1);

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

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

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

I'm not sure why this works, but as far as I reason (with help from Skeet) if i have a static class

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

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

The code:

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

will throw with an exception, because somehow this resolves to the .ctor, instead of the .cctor of the class.
If I use an explicitly static class, it is treated like an abstract sealed class, so the exception is that an abstract class cannot be instantiated, and if I use a regular class with a static constructor, the exception is that the type initializer is not callable.

But if I use the Invoke overload with two parameters (instance, params), like this:

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

explicitly stating that I am invoking a static method (that's the meaning of the first null - no instance == static), this works and initializes the class.


That said, static constructors are strange beasts. Invoking one in this way will call the static constructor even if it was already executed, i.e., this code:

Console.WriteLine(Statics1.Value1);

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

will call the static constructor twice. So if your cctors have potentially important sideeffects, such as creating files, opening databases, etc, you might want to rethink this approach.

Also, even though I prefer static constructors for reasons of readability, from a performance perspective, field initializers are a bit faster than static constructors

梦纸 2024-10-15 15:04:21

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

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

public static class MyStatic
{
    public static string SomeToolMethod()
    {
        return "Hello";
    }
}

public class MyStaticWrapper // or proxy, technically?
{
    public static string SomeToolMethod()
    {
        return MyStatic.SomeToolMethod();
    }
}

fooType.TypeInitializer.Invoke(new MyStaticWrapper()); /// untested, not sure of syntax here

EDIT: explicitly won't work as-is, as poster states can't know the types in advance. Leaving here as might help clarification for future readers ...

If I understand your needs correctly -- in similar circumstances I create a wrapper that references the static class but remains part of the test suite. You can then instantiate the wrapper and have the static initialized on demand. It'd mean you can leave the architecture unchanged, and keep the wrapper as part of the test framework.

public static class MyStatic
{
    public static string SomeToolMethod()
    {
        return "Hello";
    }
}

public class MyStaticWrapper // or proxy, technically?
{
    public static string SomeToolMethod()
    {
        return MyStatic.SomeToolMethod();
    }
}

fooType.TypeInitializer.Invoke(new MyStaticWrapper()); /// untested, not sure of syntax here
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文