aboutsummaryrefslogtreecommitdiffhomepage
path: root/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
diff options
context:
space:
mode:
authorGravatar Jon Skeet <jonskeet@google.com>2018-04-26 16:31:26 +0100
committerGravatar Jon Skeet <skeet@pobox.com>2018-04-27 16:47:46 +0100
commit1b219a174c413af3b18a082a4295ce47932314c4 (patch)
treeb9ce5722b2b02b6dbd4fc3e0221495baa7a30742 /csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
parenta21f225824e994ebd35e8447382ea4e0cd165b3c (diff)
Fix to allow AOT compilers to play nicely with reflection
With this fix, Unity using IL2CPP should work with one of two approaches: - Call `FileDescriptor.ForceReflectionInitialization<T>` for every enum present in generated code (including oneof case enums) - Ensure that IL2CPP uses the same code for int and any int-based enums The former approach is likely to be simpler, unless IL2CPP changes its default behavior. We *could* potentially generate the code automatically, but that makes me slightly uncomfortable in terms of generating code that's only relevant in one specific scenario. It would be reasonably easy to write a tool (separate from protoc) to generate the code required for any specific set of assemblies, so that Unity users can include it in their application. We can always decide to change to generate it automatically later.
Diffstat (limited to 'csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs')
-rw-r--r--csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs41
1 files changed, 23 insertions, 18 deletions
diff --git a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
index 80d5c774..18a70b80 100644
--- a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
+++ b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
@@ -50,6 +50,29 @@ namespace Google.Protobuf.Reflection
/// </summary>
internal static class ReflectionUtil
{
+ static ReflectionUtil()
+ {
+ ForceInitialize<string>(); // Handles all reference types
+ ForceInitialize<int>();
+ ForceInitialize<long>();
+ ForceInitialize<uint>();
+ ForceInitialize<ulong>();
+ ForceInitialize<float>();
+ ForceInitialize<double>();
+ ForceInitialize<bool>();
+ ForceInitialize<int?>();
+ ForceInitialize<long?>();
+ ForceInitialize<uint?>();
+ ForceInitialize<ulong?>();
+ ForceInitialize<float?>();
+ ForceInitialize<double?>();
+ ForceInitialize<bool?>();
+ ForceInitialize<SampleEnum>();
+ SampleEnumMethod();
+ }
+
+ internal static void ForceInitialize<T>() => new ReflectionHelper<IMessage, T>();
+
/// <summary>
/// Empty Type[] used when calling GetProperty to force property instead of indexer fetching.
/// </summary>
@@ -163,7 +186,6 @@ namespace Google.Protobuf.Reflection
{
try
{
- PreventLinkerFailures();
// Try to do the conversion using reflection, so we can see whether it's supported.
MethodInfo method = typeof(ReflectionUtil).GetMethod(nameof(SampleEnumMethod));
// If this passes, we're in a reasonable runtime.
@@ -176,23 +198,6 @@ namespace Google.Protobuf.Reflection
}
}
- /// <summary>
- /// This method is effectively pointless, but only called once. It's present (and called)
- /// to avoid the Unity linker from removing code that's only called via reflection.
- /// </summary>
- private static void PreventLinkerFailures()
- {
- // Exercise the method directly. This should avoid any pro-active linkers from stripping
- // the method out.
- SampleEnum x = SampleEnumMethod();
- if (x != SampleEnum.X)
- {
- throw new InvalidOperationException("Failure in reflection utilities");
- }
- // Make sure the ReflectionHelper parameterless constructor isn't removed...
- var helper = new ReflectionHelper<int, int>();
- }
-
public enum SampleEnum
{
X