Call Control Static Constructor

In my static custom attribute constructor, I look at the loaded assembly for all classes decorated with my attribute and perform some actions on them.

I would like the static constructor to be called as soon as possible at runtime, preferably before the static void Main() entry point is executed.

Currently, it is called only after I called some call to this attribute. I could make such a call elsewhere in my program, but ideally, the attribute functionality would be autonomous.

Looking for answers, I read this on MSDN :

The user cannot control when the static constructor is executed in the program.

But, of course, there is some tricky, crafty, or mischievous workaround to get the static constructor to be called by ASAP. Perhaps you can use an attribute, reflection, or some other magic. Can this be done?

Because people will undoubtedly tell me that there is no reason to do what I ask, I present my purpose and my code: I try to use attributes to declaratively configure the db4o factory. If my static constructor attribute is called after I have already established a connection, it has no effect and is useless. Therefore, it must be called before my program gets the opportunity to establish such a connection.

 [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] sealed public class CascadeOnUpdateAttribute : Attribute { public bool Flag { get; private set; } public CascadeOnUpdateAttribute() : this(true) { } public CascadeOnUpdateAttribute(bool flag) { Flag = flag; } static CascadeOnUpdateAttribute() { var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies() from type in assembly.GetTypes() from attribute in type.GetCustomAttributes(typeof(CascadeOnUpdateAttribute), false).Cast<CascadeOnUpdateAttribute>() select new { Type = type, Cascade = attribute.Flag }; foreach (var target in targets) { Db4oFactory.Configure().ObjectClass(target.Type).CascadeOnUpdate(target.Cascade); } } } 

Update:

I ended up using an abstract attribute with a static method. That way, I can get as many attributes as I like, and they will all be applied to the specified config by calling this one method.

 public abstract class Db4oAttribute : Attribute { public abstract void Configure(IConfiguration config, Type type); public static void ApplyAttributes(IConfiguration config) { var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies() from type in assembly.GetTypes() from attribute in type.GetCustomAttributes(typeof(Db4oAttribute), false).Cast<Db4oAttribute>() select new { Type = type, Attribute = attribute }; foreach (var target in targets) { target.Attribute.Configure(config, target.Type); } } } 

And the call site:

 Db4oAttribute.ApplyAttributes(Db4oFactory.Configure()); _db = Db4oFactory.OpenFile("Test.db4o"); 
+4
source share
4 answers

As Mark says, I would have done it explicitly in Main , if I were you.

You can invoke a type initializer for a type by explicitly using the Type.TypeInitializer property and referring to it. However, this will lead to a restart, even if it is already running, which may lead to unexpected results.

I personally would completely move this code from the static initializer. This is the configuration code - why not just make it a static method that can be called explicitly? I'm not even sure that I will have this in the attribute class itself, but at least I explicitly call:

 CascadeOnUpdateAttribute.ConfigureDb4oFactories(); 

clearer than calling a dummy method or force type initialization in some other way, just to get a side effect.

+3
source

If you want the static constructor to be called, add a method to the dummy type and just call it at the beginning of your code ( Main , etc.); if it is a trivial / empty method, you can mark it without insertion, etc.

 class SomeType { static SomeType() { Console.WriteLine("SomeType.cctor"); } [MethodImpl(MethodImplOptions.NoInlining)] public static void Init() { } } static class Program { static void Main() { SomeType.Init(); Console.WriteLine("hi"); } } 

You can use reflection to invoke the static constructor, but I do not recommend it; if you use reflection, you can call .cctor several times, and that will never be good ...

+3
source

You can avoid the static dummy method by calling

 System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(CascadeOnUpdateAttribute).TypeHandle) 
+2
source

I think using a static constructor smells; I would consider reorganizing your code to control access to the db4o factory so that you do not need to use it.

+1
source

All Articles