I'm not completely up to date on module initialization in CLR. Is there still no native language support for it? I only know this 7 year old workaround, but this is done after building:
http://einaregilsson.com/module-initializers-in-csharp/ Also I just found this post about a nuget package:
http://geertvanhorrik.com/2013/06/28/assembly-constructors-and-initializers-using-c/ Also not a good solution for including it in a library... Would be a bit sad if Microsoft still offers no support to access this CLR feature. I understand that static constructors are only called when the type is referenced for the first time.
Another possible (also if not as performant) option I successfully tried was reflection.
https://github.com/Falco20019/protobuf/commit/74e5a82593787610f2207423bf3a8a8449a78813 By introducing a common interface, you can look them up in the AppDomain. Here is the test class I used to generate a TypeRegistry from all currently loaded assemblies. This is not cached but calculated on request since new assemblies can be introduced as you said.
public static TypeRegistry GetTypeRegistry()
{
List<FileDescriptor> descriptors = new List<FileDescriptor>();
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(IReflection).IsAssignableFrom(p) && !p.IsInterface)
.ToList()
.ForEach(type =>
{
var pi = type.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static);
var value = pi.GetValue(null);
descriptors.Add((FileDescriptor)value);
});
return TypeRegistry.FromFiles(descriptors);
}
Calling GetValue on the property initializes the type and returns the descriptor. If you only want to call your static constructor for all classes, you could use
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);
This is better than invoking
TypeInitializer
which leads to the constructor being called multiple times (as you also wrote on StackOverflow 6 years ago :) ).
I also thought about just using IMessage for the lookup and use Descriptor to initialize the TypeRegistry with FromMessages, but this would finds a lot more types which would make the reflection part slower.