Selaa lähdekoodia

Use the original name in JSON formatting.

(JSON parsing already does the right thing.)
Jon Skeet 9 vuotta sitten
vanhempi
commit
790f4c8e37

+ 2 - 0
csharp/src/Google.Protobuf/Google.Protobuf.nuspec

@@ -33,10 +33,12 @@
         <dependency id="System.Linq.Expressions" version="4.0.0" />
         <dependency id="System.Linq.Expressions" version="4.0.0" />
         <dependency id="System.ObjectModel" version="4.0.0" />
         <dependency id="System.ObjectModel" version="4.0.0" />
         <dependency id="System.Reflection" version="4.0.0" />
         <dependency id="System.Reflection" version="4.0.0" />
+        <dependency id="System.Reflection.Extensions" version="4.0.0" />
         <dependency id="System.Runtime" version="4.0.0" />
         <dependency id="System.Runtime" version="4.0.0" />
         <dependency id="System.Runtime.Extensions" version="4.0.0" />
         <dependency id="System.Runtime.Extensions" version="4.0.0" />
         <dependency id="System.Text.Encoding" version="4.0.0" />
         <dependency id="System.Text.Encoding" version="4.0.0" />
         <dependency id="System.Text.RegularExpressions" version="4.0.0" />
         <dependency id="System.Text.RegularExpressions" version="4.0.0" />
+        <dependency id="System.Threading" version="4.0.0" />
       </group>
       </group>
     </dependencies>
     </dependencies>
   </metadata>
   </metadata>

+ 43 - 2
csharp/src/Google.Protobuf/JsonFormatter.cs

@@ -39,6 +39,7 @@ using Google.Protobuf.WellKnownTypes;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Reflection;
 
 
 namespace Google.Protobuf
 namespace Google.Protobuf
 {
 {
@@ -420,9 +421,10 @@ namespace Google.Protobuf
             }
             }
             else if (value is System.Enum)
             else if (value is System.Enum)
             {
             {
-                if (System.Enum.IsDefined(value.GetType(), value))
+                string name = OriginalEnumValueHelper.GetOriginalName(value);
+                if (name != null)
                 {
                 {
-                    WriteString(writer, value.ToString());
+                    WriteString(writer, name);
                 }
                 }
                 else
                 else
                 {
                 {
@@ -877,5 +879,44 @@ namespace Google.Protobuf
                 TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
                 TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
             }
             }
         }
         }
+
+        // Effectively a cache of mapping from enum values to the original name as specified in the proto file,
+        // fetched by reflection.
+        // The need for this is unfortunate, as is its unbounded size, but realistically it shouldn't cause issues.
+        private static class OriginalEnumValueHelper
+        {
+            // TODO: In the future we might want to use ConcurrentDictionary, at the point where all
+            // the platforms we target have it.
+            private static readonly Dictionary<System.Type, Dictionary<object, string>> dictionaries
+                = new Dictionary<System.Type, Dictionary<object, string>>();
+            
+            internal static string GetOriginalName(object value)
+            {
+                var enumType = value.GetType();
+                Dictionary<object, string> nameMapping;
+                lock (dictionaries)
+                {
+                    if (!dictionaries.TryGetValue(enumType, out nameMapping))
+                    {
+                        nameMapping = GetNameMapping(enumType);
+                        dictionaries[enumType] = nameMapping;
+                    }
+                }
+
+                string originalName;
+                // If this returns false, originalName will be null, which is what we want.
+                nameMapping.TryGetValue(value, out originalName);
+                return originalName;
+            }
+
+            private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
+                enumType.GetTypeInfo().DeclaredFields
+                    .Where(f => f.IsStatic)
+                    .ToDictionary(f => f.GetValue(null),
+                                  f => f.GetCustomAttributes<OriginalNameAttribute>()
+                                        .FirstOrDefault()
+                                        // If the attribute hasn't been applied, fall back to the name of the field.
+                                        ?.Name ?? f.Name);
+        }
     }
     }
 }
 }