|
|
@ -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); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|