72

I'm running into a behavior I wasn't expecting when using Enum.TryParse.

If I have an enum:

public enum MyEnum
{
  ValueA,
  ValueB,
  ValueC
}

And then I pass a numeric value (as a string) into Enum.TryParse, like:

MyEnum outputEnum;
bool result = Enum.TryParse("1234", out outputEnum);

Despite the string "1234" not being a possible value, result will come back as true, and my outputEnum will have a value of 1234.

Is there a way I can avoid this sort of behavior? I'm trying to write a function which will process arbitrary string input as an enum, and this has thrown a bit of a monkeywrench in my bad-input detection.

mweber
  • 1,292
  • 2
  • 10
  • 13

4 Answers4

91

This behavior is by design.

The documentation says:

. If value is the string representation of an integer that does not represent an underlying value of the TEnum enumeration, the method returns an enumeration member whose underlying value is value converted to an integral type. If this behavior is undesirable, call the IsDefined method to ensure that a particular string representation of an integer is actually a member of TEnum.

Call Enum.IsDefined to veryify that the value you parsed actually exists in this particular enum.

If you're dealing with [Flags] enums (bitmasks), it'll get more complicated.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
9

Use it like this

bool result = Enum.TryParse("1234", out MyEnum outputEnum) && Enum.IsDefined(typeof(MyEnum), outputEnum);

The value of result will be false but the value of outputEnum is still 1234

Abbas Ghomi
  • 139
  • 1
  • 7
  • 1
    Be aware that Enum.IsDefined uses reflection which can be slow, if you are looking for a fully optimized solution in terms of performance. You can read more about it here: https://stackoverflow.com/a/2605417/1754152 – Mario Aug 07 '20 at 09:03
0

If you want to avoid numeric values being accepted entirely and want to avoid Enum.IsDefined(), you can add a check to the condition to verify that the string is not numeric. There's a bunch of different ways to do that with different trade-offs but, for example you could do this:

string valueToParse = "1234";
bool result = !valueToParse.All(char.IsDigit) && Enum.TryParse(valueToParse, out MyEnum outputEnum);
Rob Streeting
  • 1,675
  • 3
  • 16
  • 27
0

as stated before, this is by design. If you want to avoid using Enum.IsDefined for performance purposes, then the hack is pretty simple:

Enum.TryParse("1234", out MyEnum outputEnum) && !int.TryParse(outputEnum.ToString(), out int shouldBeIgnored)