Fix build error for missing method Enum.GetValues() on some platforms

pull/288/head
csharptest 10 years ago committed by rogerk
parent e234691b67
commit 1e29e701a7
  1. 28
      src/ProtocolBuffers.Serialization/AbstractReader.cs
  2. 81
      src/ProtocolBuffers/CodedInputStream.cs
  3. 126
      src/ProtocolBuffers/EnumLite.cs

@ -469,23 +469,12 @@ namespace Google.ProtocolBuffers.Serialization
rawValue = null; rawValue = null;
if (ReadEnum(ref rawValue)) if (ReadEnum(ref rawValue))
{ {
if (Enum.IsDefined(typeof(T), rawValue)) if (!EnumParser<T>.TryConvert(rawValue, ref value))
{ {
if (rawValue is int) value = default(T);
{ return false;
value = (T) rawValue;
}
else if (rawValue is string)
{
value = (T) Enum.Parse(typeof(T), (string) rawValue, false);
}
else
{
value = default(T);
return false;
}
return true;
} }
return true;
} }
return false; return false;
} }
@ -560,13 +549,10 @@ namespace Google.ProtocolBuffers.Serialization
{ {
foreach (object rawValue in array) foreach (object rawValue in array)
{ {
if (rawValue is int) T val = default(T);
{ if (EnumParser<T>.TryConvert(rawValue, ref val))
list.Add((T) rawValue);
}
else if (rawValue is string)
{ {
list.Add((T) Enum.Parse(typeof(T), (string) rawValue, false)); list.Add(val);
} }
else else
{ {

@ -482,7 +482,7 @@ namespace Google.ProtocolBuffers
where T : struct, IComparable, IFormattable where T : struct, IComparable, IFormattable
{ {
int number = (int) ReadRawVarint32(); int number = (int) ReadRawVarint32();
if (EnumHelper<T>.TryConvert(number, ref value)) if (EnumParser<T>.TryConvert(number, ref value))
{ {
unknown = null; unknown = null;
return true; return true;
@ -1860,84 +1860,5 @@ namespace Google.ProtocolBuffers
} }
#endregion #endregion
/// <summary>
/// Helper class to make parsing enums faster.
/// </summary>
private static class EnumHelper<T> where T : struct
{
/// <summary>
/// We use the array form if all values are in the range [0, LimitForArray),
/// otherwise we build a dictionary.
/// </summary>
private const int LimitForArray = 32;
// Only one of these will be populated.
private static readonly Dictionary<int, T> dictionary;
private static readonly T?[] values;
static EnumHelper()
{
// It will actually be a T[], but the CLR will let us convert.
int[] array = (int[]) Enum.GetValues(typeof (T));
if (array.Length == 0)
{
// Empty enum; model with an empty values array.
values = new T?[0];
return;
}
int min = int.MaxValue;
int max = int.MinValue;
foreach (int number in array)
{
min = Math.Min(number, min);
max = Math.Max(number, max);
}
if (min >= 0 && max < LimitForArray)
{
values = new T?[max + 1];
foreach (int number in array)
{
values[number] = (T)(object)number;
}
}
else
{
dictionary = new Dictionary<int, T>();
foreach (int number in array)
{
dictionary[number] = (T)(object)number;
}
}
}
/// <summary>
/// Tries to convert an integer to its enum representation. This would take an out parameter,
/// but the caller uses ref, so this approach is simpler.
/// </summary>
internal static bool TryConvert(int number, ref T value)
{
if (values != null)
{
if (number < 0 || number >= values.Length)
{
return false;
}
T? maybeValue = values[number];
if (maybeValue != null)
{
value = maybeValue.Value;
return true;
}
return false;
}
T converted;
if (dictionary.TryGetValue(number, out converted))
{
value = converted;
return true;
}
return false;
}
}
} }
} }

@ -95,26 +95,140 @@ namespace Google.ProtocolBuffers
public IEnumLite FindValueByNumber(int number) public IEnumLite FindValueByNumber(int number)
{ {
if (Enum.IsDefined(typeof(TEnum), number)) TEnum val = default(TEnum);
if (EnumParser<TEnum>.TryConvert(number, ref val))
{ {
return new EnumValue((TEnum)(object)number); return new EnumValue(val);
} }
return null; return null;
} }
public IEnumLite FindValueByName(string name) public IEnumLite FindValueByName(string name)
{ {
if (Enum.IsDefined(typeof(TEnum), name)) TEnum val = default(TEnum);
if (EnumParser<TEnum>.TryConvert(name, ref val))
{ {
object evalue = Enum.Parse(typeof(TEnum), name, false); return new EnumValue(val);
return new EnumValue((TEnum)evalue);
} }
return null; return null;
} }
public bool IsValidValue(IEnumLite value) public bool IsValidValue(IEnumLite value)
{ {
return Enum.IsDefined(typeof(TEnum), value.Number); TEnum val = default(TEnum);
return EnumParser<TEnum>.TryConvert(value.Number, ref val);
}
}
public static class EnumParser<T> where T : struct, IComparable, IFormattable
{
private static readonly Dictionary<int, T> _byNumber;
private static Dictionary<string, T> _byName;
static EnumParser()
{
int[] array;
try
{
#if CLIENTPROFILE
// It will actually be a T[], but the CLR will let us convert.
array = (int[])Enum.GetValues(typeof(T));
#else
var temp = new List<T>();
foreach (var fld in typeof (T).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
{
if (fld.IsLiteral && fld.FieldType == typeof(T))
{
temp.Add((T)fld.GetValue(null));
}
}
array = (int[])(object)temp.ToArray();
#endif
}
catch
{
_byNumber = null;
return;
}
_byNumber = new Dictionary<int, T>(array.Length);
foreach (int i in array)
{
_byNumber[i] = (T)(object)i;
}
}
public static bool TryConvert(object input, ref T value)
{
if (input is int || input is T)
{
return TryConvert((int)input, ref value);
}
if (input is string)
{
return TryConvert((string)input, ref value);
}
return false;
}
/// <summary>
/// Tries to convert an integer to its enum representation. This would take an out parameter,
/// but the caller uses ref, so this approach is simpler.
/// </summary>
public static bool TryConvert(int number, ref T value)
{
// null indicates an exception at construction, use native IsDefined.
if (_byNumber == null)
{
return Enum.IsDefined(typeof(T), number);
}
T converted;
if (_byNumber != null && _byNumber.TryGetValue(number, out converted))
{
value = converted;
return true;
}
return false;
}
/// <summary>
/// Tries to convert a string to its enum representation. This would take an out parameter,
/// but the caller uses ref, so this approach is simpler.
/// </summary>
public static bool TryConvert(string name, ref T value)
{
// null indicates an exception at construction, use native IsDefined/Parse.
if (_byNumber == null)
{
if (Enum.IsDefined(typeof(T), name))
{
value = (T)Enum.Parse(typeof(T), name, false);
return true;
}
return false;
}
// known race, possible multiple threads each build their own copy; however, last writer will win
var map = _byName;
if (map == null)
{
map = new Dictionary<string, T>(StringComparer.Ordinal);
foreach (var possible in _byNumber.Values)
{
map[possible.ToString()] = possible;
}
_byName = map;
}
T converted;
if (map.TryGetValue(name, out converted))
{
value = converted;
return true;
}
return false;
} }
} }
} }
Loading…
Cancel
Save