tags:

views:

147

answers:

5

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?

+5  A: 

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.

Mehrdad Afshari
+1 for a better answer than Jon Skeet's! You need to do something explicit, so why not make it simple and explicit rather than using reflection or custom attributes.
Joe
So there's no way of my classes to be self registering?
kyku
No there isn't.
Mehrdad Afshari
+6  A: 

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);
}
Jon Skeet
My intent is that by simply declaring a class with a static instance could trigger some behaviour. How can this be achieved in .net?
kyku
Or RuntimeHelpers.RunClassConstructor can be used.
Dzmitry Huba
@kyku: No, not without something like the code above.
Jon Skeet
@kyku: You are setting yourself up for an eventual maintenance/testing nightmare if that is your intent. That is spooky action at a distance for sure and should be avoided at all costs.
Jason
@Jason: On the other hand the maintenance/testing nightmare might as well be a result of me or a fellow programmer forgetting to call the initialization method.
kyku
@Jason. Agreed 100%! I had to suffer this kind of thing for a good year or so until we finally eradicated it from the codebase; it gobbled up dev time, especially when static initialisers required other static initialisers to run first (the horror). It quickly turns into a spaghetti mess.@kyku: Follow the principle of least surprise. Why should anyone have to call numerous static initialise methods just to use an instance of a class or call some other static methods? If it's hard to understand, easy to misuse and a maintenance problem, why do it in the first place?
Mark Simpson
A: 

You can run arbitrary type initializer using RuntimeHelpers.RunClassConstructor

Dzmitry Huba
+1  A: 

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.

Hans Passant
A: 

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?

kyku
It's an anti-pattern as far as I'm concerned. There may be a good reason for doing it in very specific circumstances, but I've ... yet to see a good reason for it. The reason I'm so against it is that we've had many run ins with static, implicit initialisation at work and it was extremely frustrating to work with, especially when ordering is required. It ends up being a spaghetti voodoo mess that is hard to understand and maintain. It also kills testability. I would seriously look for an alternative!
Mark Simpson