How do I write code to execute BEFORE any method in an assembly?

There is an event AppDomain.CurrentDomain.DomainUnload

that allows you to clean up static resources that do not depend on any particular instance of the class, or even any particular class. I see it as code that is executed AFTER any code in my current assembly (am I correct by the way?).

But is there a way to write a piece of code (for the current assembly) that needs to be executed BEFORE any other code in the current assembly (class library)? Or should I be looking for a more complex way to initialize some resources before running any code?

I know about static constructors, but the order of their calls is undefined. In other words, there is no guarantee that a particular static constructor will execute before other static constructors of other classes.

There is also AppDomain.AssemblyLoad

. I'm not sure if this is what I am looking for. This event fires when OTHER assemblies are being loaded rather than the current ones.

+3


source to share


5 answers


I had the same problem and solved it this way. I IAssembyInitializer

only define an interface with a method void Initialize()

. In each assembly for which I want to execute some code immediately after loading it, I define a class that implements this interface. I define an attribute to indicate classes in an assembly that implements this interface (otherwise you could find them in Reflection, but I preferred it this way):

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class AssemblyInitializerAttribute : Attribute
{
    AssemblyInitializerAttribute ()
    {
    }
    AssemblyInitializerAttribute (string typeName)
    {
        TypeName = typeName;
    }
    public string TypeName;
}

      

The attribute is set to AssemblyInfo like this:



[assembly: AssemblyInitializerAttribute ("MyNamespace.AnAssemblyInitializer")]

      

Finally, in the main assembly of the application, I register the AssemblyLoad event with a method that does all the initializations:

AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(NewAssemblyLoaded);

        static void NewAssemblyLoaded(object sender, AssemblyLoadEventArgs args)
        {
            Assembly anAssembly = args.LoadedAssembly;
            AssemblyInitializerAttribute[] initializers = (AssemblyInitializerAttribute[])anAssembly .GetCustomAttributes(typeof(AssemblyInitializerAttribute), false);
            foreach (AssemblyInitializerAttribute anInit in initializers)
            {
                Type initType = anInit.TypeName != null ? anAssembly.GetType(anInit.TypeName) : null;
                if (initType != null && initType.GetInterface("IAssemblyInitializer") != null)
                {
                    IAssemblyInitializer anInitializer = (IAssemblyInitializer)Activator.CreateInstance(initType);
                    anInitializer.Initialize();
                }
            }
        }

      

+2


source


You can use instances Lazy<T>

stored in static fields to manage static initialization order yourself. The code body of these Lazy<T>

initializer objects can reference other instances Lazy<T>

that automatically organize the initialization DAG. Obviously, you cannot have loops.

With C ++ / CLI, you can actually run the code when the assembly is loaded (module initializers). You probably don't want to go this route.



With C # this is not possible. Static maps and lazy initialization patterns are the best you get.

+1


source


You might want to scan the code and look for those places that require initialization to complete.

Then run initialization just before you need it, when initialization hasn't started yet.

In .NET, you simply don't know when the assembly will be loaded, so there is no guarantee that initialization will start on time for all scenarios.

An alternative would be for the assembly client to explicitly initiate initialization by calling the. (This will also download the assembly if not already loaded)

The AssemblyLoad event can be used both in the client to detect the loading of a specific assembly, but this will make initialization dependent on the client implementation, whereas the first solution keeps this responsibility within the assembly itself.

0


source


You can do this using Module Initializers . They are not directly supported in C #, but if you don't mind using Cecil to post your build process, you can use them.

0


source


Assuming you have no control over how your class library is used, you can write static constructors for each public / protected class in the library and invoke initialization code from each one. Obviously, the initialization code needs to keep track of the first call (via the static field), so it only runs once.

0


source







All Articles