简体   繁体   中英

Force construction of static objects

As I've learned the static objects in classes are constructed when the class is being referenced for the first time. However I'd find it sometimes usefull to initialize the statics when the program is being started. Is there some method (ie by using annotations) of enforcing it?

You can't do it with attributes (without extra code), but you can force type initialization with reflection.

For example:

foreach (Type type in assembly.GetTypes())
{
    ConstructorInfo ci = type.TypeInitializer;
    if (ci != null)
    {
         ci.Invoke(null);
    }
}

Note that this won't invoke type initializers for generic types, because you'd need to specify the type arguments. You should also note that it will force the type initializer to be run even if it's been run already which flies in the face of normal experience. I would suggest that if you really need to do this (and I'd try to change your design so you don't need it if possible) you should create your own attribute, and change the code to something like:

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);
    }
}

You could do this with LINQ, admittedly:

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);
}

Simply reference a static field on that type at the beginning of your application. There's no way of doing this solely by altering the code at the class definition site .

您可以使用RuntimeHelpers.RunClassConstructor运行任意类型的初始值设定项

The CLR supports module initializers , that's probably what you are looking for. Rather academic given your tags though, this feature is not available in the C# language, only the C++/CLI language.

The workaround is entirely painless, call a static method (Initialize?) explicitly.

Ok, I found out that this can be done in the following way. A single call to InvokeImplicitInitializers() in Main() will be call Initialize() in every class that has defined that method.

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());
        }
    }
}

What do you think? Is it a pattern or anit-pattern?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM