From 340ee42da141b5886828d283b1d83f383027ad79 Mon Sep 17 00:00:00 2001 From: Alexander Vostres Date: Thu, 5 Feb 2015 00:29:42 +0200 Subject: [PATCH 1/2] Improve Enum.TryParse performance. Fixes #70 --- src/mscorlib/src/System/Enum.cs | 133 +++++++++++++++++++++++++++----- 1 file changed, 114 insertions(+), 19 deletions(-) diff --git a/src/mscorlib/src/System/Enum.cs b/src/mscorlib/src/System/Enum.cs index e165374c919f..6214c045c842 100644 --- a/src/mscorlib/src/System/Enum.cs +++ b/src/mscorlib/src/System/Enum.cs @@ -388,28 +388,24 @@ private static bool TryParseEnum(Type enumType, String value, bool ignoreCase, r if (Char.IsDigit(value[0]) || value[0] == '-' || value[0] == '+') { - Type underlyingType = GetUnderlyingType(enumType); - Object temp; + bool parseSuccess = TryParseEnumValue(enumType, value, ref result); - try + if (parseSuccess) { - temp = Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture); - parseResult.parsedEnum = ToObject(enumType, temp); - return true; - } - catch (FormatException) - { // We need to Parse this as a String instead. There are cases - // when you tlbimp enums that can have values of the form "3D". - // Don't fix this code. - } - catch (Exception ex) - { - if (parseResult.canThrow) - throw; - else + try { - parseResult.SetFailure(ex); - return false; + parseResult.parsedEnum = ToObject(enumType, result); + return true; + } + catch (Exception ex) + { + if (parseResult.canThrow) + throw; + else + { + parseResult.SetFailure(ex); + return false; + } } } } @@ -474,6 +470,105 @@ private static bool TryParseEnum(Type enumType, String value, bool ignoreCase, r } } + private static bool TryParseEnumValue(Type enumType, String value, ref ulong result) + { + // No need to check for bool here since we don't want it to be parsed by value + switch (Type.GetTypeCode(enumType)) + { + case TypeCode.Char: + { + char temp; + if (Char.TryParse(value, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + case TypeCode.Byte: + { + byte temp; + if (Byte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + case TypeCode.SByte: + { + sbyte temp; + if (SByte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + case TypeCode.Int16: + { + short temp; + if (Int16.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + case TypeCode.UInt16: + { + ushort temp; + if (UInt16.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + case TypeCode.Int32: + { + int temp; + if (Int32.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + case TypeCode.UInt32: + { + uint temp; + if (UInt32.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + case TypeCode.Int64: + { + long temp; + if (Int64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + case TypeCode.UInt64: + { + ulong temp; + if (UInt64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out temp)) + { + result = (ulong)temp; + return true; + } + return false; + } + } + return false; + } + [System.Runtime.InteropServices.ComVisible(true)] public static Type GetUnderlyingType(Type enumType) { From 7c44cbb0befb13c0790de93a433c43c8ab4b3e8a Mon Sep 17 00:00:00 2001 From: Alexander Vostres Date: Sat, 7 Feb 2015 17:39:46 +0200 Subject: [PATCH 2/2] Enum.TryParse: ensure backwards compatibility for enums based on floats and IntPtr --- src/mscorlib/src/System/Enum.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/mscorlib/src/System/Enum.cs b/src/mscorlib/src/System/Enum.cs index 6214c045c842..46cce953993d 100644 --- a/src/mscorlib/src/System/Enum.cs +++ b/src/mscorlib/src/System/Enum.cs @@ -388,7 +388,7 @@ private static bool TryParseEnum(Type enumType, String value, bool ignoreCase, r if (Char.IsDigit(value[0]) || value[0] == '-' || value[0] == '+') { - bool parseSuccess = TryParseEnumValue(enumType, value, ref result); + bool parseSuccess = TryParseEnumValue(enumType, value, ref result, ref parseResult); if (parseSuccess) { @@ -408,6 +408,10 @@ private static bool TryParseEnum(Type enumType, String value, bool ignoreCase, r } } } + else if (parseResult.m_failure != ParseFailureKind.None) + { + return false; + } } String[] values = value.Split(enumSeperatorCharArray); @@ -470,11 +474,13 @@ private static bool TryParseEnum(Type enumType, String value, bool ignoreCase, r } } - private static bool TryParseEnumValue(Type enumType, String value, ref ulong result) + private static bool TryParseEnumValue(Type enumType, String value, ref ulong result, ref EnumResult parseResult) { - // No need to check for bool here since we don't want it to be parsed by value switch (Type.GetTypeCode(enumType)) { + case TypeCode.Boolean: + return false; + case TypeCode.Char: { char temp; @@ -565,8 +571,13 @@ private static bool TryParseEnumValue(Type enumType, String value, ref ulong res } return false; } + default: + { + // This is needed for backwards compatibility + parseResult.SetFailure(ParseFailureKind.Argument, "Arg_MustBeEnumBaseTypeOrEnum", null); + return false; + } } - return false; } [System.Runtime.InteropServices.ComVisible(true)]