开发者

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 someti开发者_Go百科mes 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.


You can run arbitrary type initializer using 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?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜