diff --git a/CodeJam.Main.Tests/EnumHelperTests.cs b/CodeJam.Main.Tests/EnumHelperTests.cs index 58f0d4959..8ca5ad064 100644 --- a/CodeJam.Main.Tests/EnumHelperTests.cs +++ b/CodeJam.Main.Tests/EnumHelperTests.cs @@ -40,7 +40,7 @@ private enum Flags : byte D = 0x8, // ReSharper disable once InconsistentNaming CD = C | D, - Dx = D | 0x20 + Dx = D | 0x20, } private const Flags Ab = Flags.A | Flags.B; @@ -77,15 +77,15 @@ private enum NoFlags : byte private const NoFlags EfU = NoFlags.E | NoFlags.F | NoFlagsUndef; // ReSharper restore BitwiseOperatorOnEnumWithoutFlags - public enum NameDescEnum + public enum NameDescEnum : long { [Display(Name = "Field 1", Description = "Field 1 Desc")] - Field1, + Field1 = long.MinValue, [Display] - Field2, + Field2 = 0, - Field3 + Field3 = long.MaxValue } #endregion @@ -425,5 +425,21 @@ public static void TestSetOrClearFlag() [TestCase(NameDescEnum.Field2, ExpectedResult = "Field2")] [TestCase(NameDescEnum.Field3, ExpectedResult = "Field3")] public string TestGetDisplay(NameDescEnum value) => EnumHelper.GetEnumValue(value).ToString(); + + [Test] + public void TestNegativeValues() + { + IsTrue(EnumHelper.IsDefined(NameDescEnum.Field1)); + IsFalse(EnumHelper.IsFlagsEnum()); + AreEqual( + NameDescEnum.Field1, + EnumHelper.TryParse(nameof(NameDescEnum.Field1))); + AreEqual( + NameDescEnum.Field1, + EnumHelper.TryParse(long.MinValue.ToString())); + AreEqual( + "Field2, Field3, Field1", + EnumHelper.GetNameValues().Select(kvp => kvp.Key).Join(", ")); + } } } \ No newline at end of file diff --git a/CodeJam.Main/EnumHelper.Holder.cs b/CodeJam.Main/EnumHelper.Holder.cs index 6ba59d509..248ddb7b9 100644 --- a/CodeJam.Main/EnumHelper.Holder.cs +++ b/CodeJam.Main/EnumHelper.Holder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -93,6 +94,27 @@ private static TEnum[] GetNonDefaultFlagsCore() => .Distinct() .ToArray(); + private static ulong ToUInt64(object value) + { + switch (Convert.GetTypeCode(value)) + { + case TypeCode.Boolean: + case TypeCode.Char: + case TypeCode.Byte: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + return Convert.ToUInt64(value, CultureInfo.InvariantCulture); + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + return unchecked((ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture)); + default: + throw CodeExceptions.UnexpectedArgumentValue(nameof(value), value); + } + } + // NB: simple implementation here // as result of method call is cached. private static TEnum[] GetNonDefaultUniqueFlagsCore() @@ -100,7 +122,7 @@ private static TEnum[] GetNonDefaultUniqueFlagsCore() // THANKSTO: Maciej Hehl, https://stackoverflow.com/a/2709523 static int GetNumberOfSetBits(TEnum value) { - var i = Convert.ToUInt64(value); + var i = ToUInt64(value); i -= (i >> 1) & 0x5555555555555555UL; i = (i & 0x3333333333333333UL) + ((i >> 2) & 0x3333333333333333UL); return (int)(unchecked(((i + (i >> 4)) & 0xF0F0F0F0F0F0F0FUL) * 0x101010101010101UL) >> 56);