Yes, that approach looks like it would handle all the currently-loaded 
assemblies. I'm not sure that it would help with assemblies which were 
referenced but hadn't yet been loaded.

Ultimately, it depends on what this is for - personally I'd expect that in 
most cases it would be fine just to explicitly state up-front which 
descriptors (or at least assemblies) were involved.

Jon


On Wednesday, 9 March 2016 17:15:23 UTC, Benjamin Krämer wrote:
>
> 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