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 protobuf+unsubscr...@googlegroups.com.
To post to this group, send email to protobuf@googlegroups.com.
Visit this group at https://groups.google.com/group/protobuf.
For more options, visit https://groups.google.com/d/optout.

Reply via email to