C# 静态物体的力结构

C# 静态物体的力结构,c#,.net,C#,.net,据我所知,类中的静态对象是在第一次引用类时构造的。然而,我发现有时在程序启动时初始化静态是有用的。是否有某种方法(即使用注释)来强制执行它?只需在应用程序开始时引用该类型上的静态字段即可。仅仅通过更改类定义站点上的代码是无法做到这一点的。您不能使用属性(没有额外的代码)来实现这一点,但您可以使用反射强制类型初始化 例如: foreach (Type type in assembly.GetTypes()) { ConstructorInfo ci = type.TypeInitializ

据我所知,类中的静态对象是在第一次引用类时构造的。然而,我发现有时在程序启动时初始化静态是有用的。是否有某种方法(即使用注释)来强制执行它?

只需在应用程序开始时引用该类型上的静态字段即可。仅仅通过更改类定义站点上的代码是无法做到这一点的。

您不能使用属性(没有额外的代码)来实现这一点,但您可以使用反射强制类型初始化

例如:

foreach (Type type in assembly.GetTypes())
{
    ConstructorInfo ci = type.TypeInitializer;
    if (ci != null)
    {
         ci.Invoke(null);
    }
}
请注意,这不会为泛型类型调用类型初始值设定项,因为您需要指定类型参数。您还应该注意,它将强制运行类型初始值设定项,即使它已经运行过,这与正常的经验是背道而驰的。我建议,如果您真的需要这样做(我会尝试更改您的设计,以便尽可能不需要它),您应该创建自己的属性,并将代码更改为类似以下内容:

foreach (Type type in assembly.GetTypes())
{
    if (type.GetCustomAttributes(typeof(..., false)).Length == 0)
    {
        continue;
    }
    ConstructorInfo ci = type.TypeInitializer;
    if (ci != null)
    {
         ci.Invoke(null, null);
    }
}
诚然,你可以用LINQ做到这一点:

var initializers = from type in assembly.GetTypes()
                   let initializer = type.TypeInitializer
                   where initializer != null &&
                         type.GetCustomAttributes(typeof(..., false).Length > 0
                   select initializer;
foreach (ConstructorInfo initializer in initializers)
{
    initializer.Invoke(null, null);
}

您可以使用CLR支持的

来运行任意类型的初始值设定项,这可能就是您想要的。但是,考虑到您的标记,此功能在C语言中不可用,仅在C++/CLI语言中可用


解决方法完全没有痛苦,显式调用静态方法(Initialize?)。

好的,我发现这可以通过以下方式完成。对Main()中invokeImplicitializers()的单个调用将是定义该方法的每个类中的call Initialize()

using System;
using System.Reflection;

namespace Test
{
    public class Class1
    {
        static Class1()
        {
            Console.WriteLine("Class1: static constructor");
        }

        public static void Initialize()
        {
            Console.WriteLine("Class1: initialize method");
        }
    }

    public static class Class2
    {
        public static void Initialize()
        {
            Console.WriteLine("Class2: initialize method");
        }
    }


    class MainClass
    {
        public static void InvokeImplicitInitializers(Assembly assembly)
        {
            foreach (Type type in assembly.GetTypes())
            {
                MethodInfo mi = type.GetMethod("Initialize");
                if (mi != null) 
                {
                    mi.Invoke(null, null);
                }
            }
        }

        public static void Main (string[] args)
        {
            InvokeImplicitInitializers(Assembly.GetCallingAssembly());
        }
    }
}

你觉得怎么样?它是模式还是anit模式?

我的意图是,通过简单地用静态实例声明一个类,就可以触发一些行为。如何在.net或RuntimeHelpers中实现这一点?可以使用RuntimeHelpers.RunClassConstructor。@kyku:如果这是您的意图,您正在为最终的维护/测试噩梦做准备。这无疑是一个令人毛骨悚然的动作,应该不惜一切代价避免。@Jason:另一方面,维护/测试噩梦可能是由于我或其他程序员忘记调用初始化方法造成的。@Jason。100%同意!我不得不忍受这种事情整整一年左右,直到我们最终从代码库中根除它;它占用了开发时间,特别是当静态初始化程序需要其他静态初始化程序首先运行时(最糟糕的情况)。它很快就会变成一团意大利面条@基库:遵循最小意外的原则。为什么任何人都必须调用大量静态初始化方法才能使用类的实例或调用其他静态方法?如果它很难理解,很容易被误用,并且存在维护问题,那么首先为什么要这么做?+1比Jon Skeet的答案更好!你需要做一些显式的事情,所以为什么不让它变得简单和显式,而不是使用反射或自定义属性。所以我的类不可能是自注册的?就我而言,这是一种反模式。在非常特殊的情况下这样做可能有很好的理由,但我。。。但我还没有找到一个好的理由。我如此反对它的原因是,我们在工作中遇到了许多静态、隐式初始化的磨合,使用它非常令人沮丧,尤其是在需要订购时。它最终变成了一团难以理解和维护的意大利面巫毒。它还破坏了可测试性。我会认真地寻找另一个选择!