Hi Jon,

Am Mittwoch, 9. März 2016 13:59:32 UTC+1 schrieb Jon Skeet:
>
> Indeed there isn't. It's not clear to me at what point messages would get 
> registered - after all, a new assembly with extra messages could be loaded 
> at any point.
>

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.

-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/protobuf.
For more options, visit https://groups.google.com/d/optout.

Reply via email to