-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Enum.TryParse overloads that allow restricting what input is considered valid #29167
Comments
Definitely agree on this. Had some headaches debugging programs because of this. 😬 Ultimately I settled onto a combination of |
Thanks for the proposal, in order to consider this we would need a formal API Proposal so that we can take this up for review. You can find more info on how to author one here https://github.com/dotnet/runtime/blob/master/docs/project/api-review-process.md |
Background and MotivationMake enums easier parseable with specific restrictions or relaxations as required by the developer. Provides a solution to a series of issues such as #28841. Provides various sources of issues with enums ways to implement solutions to these problems wholly or partially upon the proposed API's, #36502 (Microsoft.Extensions.Configuration), #35900 (System.Text.Json) and others. Proposed APIAPI signature diff that is being proposed: namespace System
{
+ [Flags]
+ public enum EnumStyles
+ {
+ None,
+ IgnoreCase = 1,
+ Defined = 2,
+ Single = 4,
+ Names = 8,
+ }
public class Enum
{
+ public static object Parse(Type enumType, string value, EnumStyles enumStyles = default, NumberStyles numberStyles = NumberStyles.Integer, IFormatProvider provider = null);
+ public static object Parse(Type enumType, ReadOnlySpan<char> value, EnumStyles enumStyles = default, NumberStyles numberStyles = NumberStyles.Integer, IFormatProvider provider = null);
+ public static bool TryParse(Type enumType, string value, out object result, EnumStyles enumStyles = default, NumberStyles numberStyles = NumberStyles.Integer, IFormatProvider provider = null);
+ public static bool TryParse(Type enumType, ReadOnlySpan<char> value, out object result, EnumStyles enumStyles = default, NumberStyles numberStyles = NumberStyles.Integer, IFormatProvider provider = null);
+ public static T Parse<T>(string value, EnumStyles enumStyles = default, NumberStyles numberStyles = NumberStyles.Integer, IFormatProvider provider = null) where T : struct, Enum;
+ public static T Parse<T>(ReadOnlySpan<char> value, EnumStyles enumStyles = default, NumberStyles numberStyles = NumberStyles.Integer, IFormatProvider provider = null) where T : struct, Enum;
+ public static bool TryParse<T>(string value, out T result, EnumStyles enumStyles = default, NumberStyles numberStyles = NumberStyles.Integer, IFormatProvider provider = null) where T : struct, Enum;
+ public static bool TryParse<T>(ReadOnlySpan<char> value, out T result, EnumStyles enumStyles = default, NumberStyles numberStyles = NumberStyles.Integer, IFormatProvider provider = null) where T : struct, Enum;
}
} The The members of this enumeration named to be logical if you read e.g. The names are also chosen to be default when Naturally I build upon #20008 and its spinoffs to provide overloads that take A possible added convenience would be to add members to Usage ExamplesInstead of hand-wrought extension methods and whatnot that do if (!TryParse("DarkGreen", out ConsoleColor result, 0
| EnumStyles.Defined
| EnumStyles.Single
| EnumStyles.Names
| EnumStyles.IgnoreCase))
Console.WriteLine("Bark"); Since Alternative DesignsOne alternative design is to get rid of RisksThe most complex part of this addition to .NET would be enforcing So if the enum being parsed is: [Flags] enum E { None, A, B, C = 4 } And |
This would help a number of problems I’ve personally run into. |
It would be useful to have overloads of
Enum.TryParse
with an argument that allows specifying what kind of inputs are valid.This would help the following primary use cases:
false
for all numeric strings. This is useful when the numeric value of the type underlying the enumeration is meaningless. E.g. the value"2"
would parse toSystem.PlatformID.Win32NT
but almost nobody cares and my guess is enumerations are quite commonly used to parse some kinds of invariant input.false
for undefined numeric strings, buttrue
for numeric strings that correspond to (a combination of) explicitly defined enumeration members. E.g. the value"16"
happily parses to(System.ConsoleColor)16
today but again almost nobody cares and this is almost always an unintended side effect of the underlying type being numeric.Secondary use cases would be:
NumberStyles
andIFormatProvider
so the number parsing can be generalized by the user. Today, for example,Enum.TryParse
simply does not take hexadecimal numbers, although it does take leading and trailing whitespace.FlagsAttribute
applied to it or not. If the enumeration defines names for the values 1, 2 and 4 and does not have aFlagsAttribute
, this is in fact the same as 2. above. If it has aFlagsAttribute
, then the value 3 would in the case ofConsoleModifiers
correspond toAlt | Shift
but in this mode Tryparse would still returnfalse
because the result is two members OR'ed together.Having a way in the BCL to specify what types of input are considered valid also helps performance, since to parse first and then to check whether the value is in fact a (combination of) explicitly defined enumeration members involves duplicating the lookup of enumeration members, either in the framework or in user code. See e.g. #28841.
There is closely related work currently underway as part of #20008.
The way to implement this would probably be to introduce overload(s) for
Enum.TryParse
andEnum.TryParse<T>
either:a) with at least one extra boolean, but that would not be enough to cover the cases mentioned.
b) to introduce an enumeration similar to Enums.NET's EnumFormat albeit vastly simplified to strip all members that have to do with number formatting and all members having to do with alternative names in attributes or descriptions.
If this is something that is considered useful, I am happy to help specifying or building this on top of #20008.
The text was updated successfully, but these errors were encountered: