27

I have a .net library dll that acts like a functional library. There are a bunch of static types along with static methods.

There is some initialization code that I need to run to set up the library ready for use.

When the assembly gets loaded is there a way to ensure that a particular method is run? Something like AppDomain.AssemblyLoad but called automatically from the assembly itself. I was thinking that maybe there is something like an AssemblyAttribute that could be used?

At the moment I have this initialization code in a static constructor but as this is a library with many entry points there is no guarantee that this particular type will be used.

Thanks!

starblue
  • 55,348
  • 14
  • 97
  • 151
sixtowns
  • 449
  • 2
  • 6
  • 13

4 Answers4

20

Yes there is - sort of.

Use the excellent little utility by by Einar Egilsson, InjectModuleInitializer.

Run this executable as a post build step to create a small .cctor function (the module initializer function) that calls a static void function of yours that takes no parameters. It would be nice if compiler gave us the ability to create .cctor(), luckily we rarely need this capability.

This is not a complete DllMain replacement, however. The CLR only calls this .cctor function prior to any methods called in your assembly, not upon assembly load. So, if you need something to happen upon assembly load, you need to have the loading code call a method directly or use the hack I detailed https://stackoverflow.com/a/9745422/240845

Community
  • 1
  • 1
mheyman
  • 4,211
  • 37
  • 34
14

The following solution is possible only when you have control over the main executing assembly, i.e. it's not suitable for standalone libraries meant for distribution

I've had a similar problem and solved it by creating an assembly-targeted attribute 'InitializeOnLoad' with a Type parameter. Then, in the main executable, I've added a trivial AppDomain.AssemblyLoaded handler, which scans the newly loaded assembly for the aforementioned attribute and calls System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor() on them.

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class InitializeOnLoadAttribute : Attribute
{
    Type type;

    public InitializeOnLoadAttribute(Type type) { this.type = type; }

    public Type Type { get { return type; } }
}

// somewhere very early in main exe initialization
AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(AssemblyInitializer);

static void AssemblyInitializer(object sender, AssemblyLoadEventArgs args)
{
    // force static constructors in types specified by InitializeOnLoad
    foreach (InitializeOnLoadAttribute attr in args.LoadedAssembly.GetCustomAttributes(typeof(InitializeOnLoadAttribute), false))
        System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(attr.Type.TypeHandle);
}

additionaly, if you are afraid that assemblies might have been loade before you hook the AssemblyLoad event, you can simply run through AppDomain.GetAssemblies() and call the 'initializer' for them.

Stefan Simek
  • 141
  • 1
  • 2
7

Why do you need all the data to be loaded before any of it is used, rather than just when the first type which needs it is used?

I don't believe there's any way of forcing a method to be run on assembly load, from within the assembly. You could put a static constructor in every type, but frankly I think it just makes more sense to have a single type representing that data and providing access to it - and put a static constructor on that type alone. (If you've got separate bits of data which can be used independently, perhaps create separate types for them.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I didn't mention loading any data. I really just want to make sure that the library uses a specific DateTime converter instead of the default one. (See http://stackoverflow.com/questions/458935/extend-a-typeconverter). – sixtowns Jan 19 '09 at 23:24
  • 2
    So I just want to run this code once when the assembly is loaded: TypeDescriptor.AddAttributes(typeof(DateTime), new TypeConverterAttribute(typeof(DateTimeConverterEx))); – sixtowns Jan 19 '09 at 23:25
  • So put a static constructor in every type which uses the converter. It's unfortunate, but that's the price to be paid for static state :( – Jon Skeet Jan 19 '09 at 23:28
  • (Apologies for assuming you meant "load" by "initialize" btw.) – Jon Skeet Jan 19 '09 at 23:28
  • I thought this might be the case. The question title was misleading because it said 'data' - I've changed it. Cheers. – sixtowns Jan 19 '09 at 23:36
  • 6
    Actually one might want to have code run on assembly load - for instance if there is an costly initialization involved, which might better be resolved in one place. Of course one can work around that by manually looking for some initialization routine in an assembly and executing it, but the question whether the framework provides a built-in method for doing this does have its place. – EFraim Apr 15 '12 at 10:45
  • 2
    @JonSkeet "Why do you need all the data to be loaded before any of it is used?" Suppose there is a 3rd-party library with some type `Vector3`. There is also a library with an operation registry where you can register an operation (say, addition or conversion) for any type. Now there is a geometry library which implements and uses vector operations. The geometry library wants to register the vector operations in the operation registry. This initialization should be performed on assembly load. And it's possible - just add a static constructor to the `` class. – Ark-kun Apr 02 '13 at 18:39
  • @Ark-kun: Well, it's not possible in "straight" C#. There are various options to build in a module initializer, but nothing straight out of the box. – Jon Skeet Apr 02 '13 at 18:43
2

It's possible - just add a static constructor to the <Module> class. I don't know how to accomplish this without IL modification though.

Ark-kun
  • 6,358
  • 2
  • 34
  • 70