1251

What's the best way to convert a string to an enumeration value in C#?

I have an HTML select tag containing the values of an enumeration. When the page is posted, I want to pick up the value (which will be in the form of a string) and convert it to the corresponding enumeration value.

In an ideal world, I could do something like this:

StatusEnum MyStatus = StatusEnum.Parse("Active");

but that isn't valid code.

David Klempfner
  • 8,700
  • 20
  • 73
  • 153
Ben Mills
  • 27,454
  • 14
  • 42
  • 38

29 Answers29

2065

In .NET Core and .NET Framework ≥4.0 there is a generic parse method:

Enum.TryParse("Active", out StatusEnum myStatus);

This also includes C#7's new inline out variables, so this does the try-parse, conversion to the explicit enum type and initialises+populates the myStatus variable.

If you have access to C#7 and the latest .NET this is the best way.

Original Answer

In .NET it's rather ugly (until 4 or above):

StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);

I tend to simplify this with:

public static T ParseEnum<T>(string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

Then I can do:

StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");

One option suggested in the comments is to add an extension, which is simple enough:

public static T ToEnum<T>(this string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();

Finally, you may want to have a default enum to use if the string cannot be parsed:

public static T ToEnum<T>(this string value, T defaultValue) 
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    T result;
    return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

Which makes this the call:

StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);

However, I would be careful adding an extension method like this to string as (without namespace control) it will appear on all instances of string whether they hold an enum or not (so 1234.ToString().ToEnum(StatusEnum.None) would be valid but nonsensical) . It's often be best to avoid cluttering Microsoft's core classes with extra methods that only apply in very specific contexts unless your entire development team has a very good understanding of what those extensions do.

Panzercrisis
  • 4,590
  • 6
  • 46
  • 85
Keith
  • 150,284
  • 78
  • 298
  • 434
  • 24
    If performace is important (which always is) chk answer given by Mckenzieg1 below : http://stackoverflow.com/questions/16100/converting-a-string-to-an-enumeration-value-in-c/38711#38711 – Nash Jul 19 '09 at 19:04
  • 35
    @avinashr is right about @McKenzieG1's answer, but it isn't ALWAYS important. For instance it would be a pointless micro optimisation to worry about enum parsing if you were making a DB call for each parse. – Keith Jul 19 '09 at 20:19
  • 1
    make it an extension method and it'll be perfect – H.M. Aug 22 '13 at 08:57
  • 7
    @H.M. I don't think an extension is appropriate here - it's a bit of a special case and an extension would apply to _every_ string. If you really wanted to do it though it would be a trivial change. – Keith Aug 22 '13 at 10:17
  • 1
    @keith, that was my opinion because static classes are very hard to remember but one would always remembers an extension method! and yes the parameter only needs a this keyword – H.M. Aug 27 '13 at 14:32
  • 10
    How about Enum.TryParse? – Elaine Jun 03 '14 at 08:39
  • 1
    @H.M. I added an extension version, with a warning. – Keith Aug 10 '15 at 06:57
  • 1
    @Elaine Added a variant that uses `TryParse`. – Keith Aug 10 '15 at 06:58
  • 1
    @Keith: Could you elaborate a bit on what would be against making an extension method out of this? I don't understand what the problem would be. – Aage Oct 02 '15 at 09:46
  • 2
    @bump yeah - as a general rule you have to be very careful extending Microsoft's built in objects, especially very common ones like `object` or `string` as without careful namespace control this will cause your extension method to be visible on every instance across your entire code base. This isn't a problem when the method is always appropriate (for instance `.Trim()` or `.Split()`), but an enum parse is only going to apply when the string is expected to hold an enum. One or two methods like this are probably fine, but you can end up with loads of confusing ones on large projects. – Keith Oct 02 '15 at 09:54
  • 2
    @Keith Ok, but that would only apply if the namespace is included in a using right? So, `namespace SomeNameSpace.Extensions.Strings` wouldn't cause any problems? – Aage Oct 02 '15 at 10:01
  • 2
    @bump yes, exactly - that's what I mean by namespace control. You can put these extensions in namespaces to opt-in to them being available - it's a balance of convenience and code standardisation that depends very much on your development team. – Keith Oct 02 '15 at 10:03
  • 21
    very nice. you need a where T : struct in your last example. – bbrik Dec 22 '15 at 17:13
  • 1
    @bbrik it doesn't really help - what we really need is a generic enum constraint: http://stackoverflow.com/q/7244/905 – Keith Dec 23 '15 at 08:52
  • 1
    I don't see the extension as bad at all. With built in classes etc.. you can write code that is nonsensical irrespective of extensions. In order to use the extension you have a using to include it and then actually use it. Even in cases that follow the suggested use of extensions in these comments you'd still need to have error handling incase of bad input, I don't see how this is any different. Obviously you would put any and all extensions you write that extend core classes in your own namespace. – Peter Mar 16 '16 at 11:36
  • 1
    @Peter I didn't say it was bad, just something you have to be careful with - an extension appears to apply to all instances of a string, but only makes sense in a subset of contexts. You can handle erroneous inputs, but that's a run time check against a compile time problem. For instance `SubString()` always applies against a string, and at run time you check whether the string is too short for the indexes provided, but `ToEnum` may or may not apply depending on what you put in. That's not bad or blocking as such, just something to be careful with. – Keith Mar 16 '16 at 17:42
  • I see what you mean, perhaps if it was called TryToEnum() then it would more explicit and make it clear that it could fail. Essentially extensions are compiler sugar, an extension method .ToEnum() is no different to Enum.Parse() - the string param cannot be guaranteed to be convertible. – Peter Mar 18 '16 at 10:43
  • As mentioned by @bbrik you need to add where T : struct in your last example, in order for the compiler to accept it. – Kenci Aug 19 '16 at 06:52
  • @Keith - I want to use the extension method where a default value can be provided. I copied and pasted your extension method but receive the error: The type 'T' must be a non-nullable value type in order to use it as parameter 'TEnum' in the generic type or method 'System.Enum.TryParse(string, bool, out TEnum)' – barrypicker Sep 13 '16 at 23:30
  • 2
    @barrypicker look comment above. `public static T ToEnum(this string value, T defaultValue) where T : struct` – Dominic Jonas Dec 13 '16 at 09:07
  • 3
    `where T : struct, IComparable` is needed to be added at the end of extension method definition. – Siyavash Hamdi Oct 16 '17 at 15:54
  • It should be as following: StatusEnum myStatus; Enum.TryParse("Active", out myStatus); – Altaf Patel Jun 22 '18 at 09:57
  • @AltafPatel in C#7 and above you don't need to declare the enum first, you can do `if(Enum.TryParse("Active", out StatusEnum myStatus)) { /* use myStatus */ }` – Keith Jun 22 '18 at 10:05
  • General note on this: you have to be very careful with putting number strings into this. They will _not_ be seen as illegal values and return the default, as you would expect, but will instead simply be parsed to integer and directly cast to the enum type, which will most likely give you a value none of your code can use. Had this problem once when the input came from a config file. So if you don't want that, best to explicitly check for numeric content in advance. – Nyerguds Jan 20 '20 at 08:52
  • So what if it applies to every string. If ToEnum is not clear enough in whatever scenario - you're definitely not meant to be a developer. Like come on... it doesn't get any clearer than that. We're borderline programming in english. – Bojidar Stanchev Jul 14 '20 at 15:35
  • @BojidarStanchev `ToEnum` is clear enough, the problem is that it _always_ extends `string`. This is fine in a small team, but if you have a large team or are working on a API it can get pretty messy if _everyone_ extends the base .NET types. There's a convention (outside .NET Core DI, which uses this deliberately) to be careful when publicly extending types like `int` and `string` without a namespace, because users of your API will get those extensions, they'll get _all_ the extensions from every library they use. – Keith Jul 15 '20 at 07:23
  • @Nyerguds - This is why you should follow McKenzieG1's answer below which recommends creating a dictionary out of enum type. This avoids boxing/unboxing and reflection used in the Enum.Parse and Enum.TryParse. As an added bonus, you get 0(1) performance and only get back actual enum values in the type. – Stack Undefined Aug 03 '20 at 17:35
  • 1
    @sanmcp I said it came from a config file. Config files are generally only read once on startup, and that particular config file belonged to a Windows service, so it should never be restarted unless something specifically needs updating. So it's a situation where performance does not matter in the slightest. – Nyerguds Aug 07 '20 at 10:22
  • I said performance is an added bonus but the important point is you don't have to `check for numeric content in advance` before converting the string to enum. If the enum is converted to a dictionary as @McKenzieG1 suggests, you don't have to be concerned with whether an argument is a number or not part of the enum. – Stack Undefined Aug 07 '20 at 15:25
  • @sanmcp Yes, if performance is critical it's worth the overhead of building up a dictionary from the reflection the first time, and then checking that instead. In fact that's how the `ToEnum` my organisation used at the time of this answer fully worked, though a little different - we would add to a `ConcurrentDictionary` for each enum type on the first parse and then use that as a cache (we had a few values that came up often out of a large set). – Keith Aug 10 '20 at 17:52
  • 1
    @sanmcp However, it _is_ a micro-optimisation, so it isn't something the vast majority of contexts _need_. Mostly you're parsing enums in serialisation: DB reads or parsing JSON/XML, and in all of those the savings for skipping the reflection are tiny compared to the DB/JSON/XML parse. Just the latency connecting to the DB or network for the JSON/XML is likely to be orders slower. So, with that in mind, I'd recommend _starting_ with the simple `Enum.TryParse` and then switching to some kind of reflection cache during optimisation if you need it. – Keith Aug 10 '20 at 17:57
  • please add vb.net code version – Yen Dang Oct 25 '21 at 09:53
  • @YenDang I'm afraid I haven't used VB.NET in about 15 years and it's basically dead (supported but no new features), but feel free to provide a VB.NET answer. The base call to `Enum.TryParse` should be the same, but it never got support for inlined `out` variables, so I'd start with the original extension method solution. – Keith Nov 03 '21 at 21:51
400

Use Enum.TryParse<T>(String, T) (≥ .NET 4.0):

StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);

It can be simplified even further with C# 7.0's parameter type inlining:

Enum.TryParse("Active", out StatusEnum myStatus);
Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
  • 54
    Add the middle boolean parameter for case-sensitivity and this is the safest and most elegant solution by far. – DanM7 Feb 28 '14 at 22:05
  • 23
    Come on, how many of you implemented that selected answer from 2008 to only scroll down and find this is the better (modern) answer. – TEK Mar 18 '16 at 14:47
  • I don't get it. `Parse` throws explanatory exceptions for what went wrong with the conversion (value was `null`, empty or no corresponding enum constant), which is way better than `TryParse`'s boolean return value (which suppresses the concrete error) – yair Jan 04 '18 at 18:42
  • 6
    Enum.TryParse(String, T) is flawed when parsing integer strings. For example, this code will successfully parse a nonsensical string as a nonsensical enum: `var result = Enum.TryParse("55", out var parsedEnum);` – Mass Dot Net Sep 11 '19 at 21:38
  • @MassDotNet: Yes, but so will `var result = (System.DayOfWeek)Enum.Parse("55")`, and `var result = (System.DayOfWeek)55`. You can't trust enums to be valid. – Eclipse Dec 03 '19 at 14:50
  • @Eclipse: I had never suggested otherwise. It's a fundamental annoyance in how Microsoft implements parsing of values as enums. – Mass Dot Net Dec 11 '19 at 19:20
  • 4
    @MassDotNet In that case add: `&& Enum.IsDefined(typeof(System.DayOfWeek), parsedEnum)` to ensure that the parsed Enum actually exists. – Walter Jun 02 '20 at 01:26
240

Note that the performance of Enum.Parse() is not ideal, because it is implemented via reflection. (The same is true of Enum.ToString(), which goes the other way.)

If you need to convert strings to Enums in performance-sensitive code, your best bet is to create a Dictionary<String,YourEnum> at startup and use that to do your conversions.

Fanblade
  • 451
  • 2
  • 9
McKenzieG1
  • 13,960
  • 7
  • 36
  • 42
  • 26
    Wow 3ms is orders of magnitude of terrible – John Stock Dec 14 '17 at 03:25
  • 3
    can you add a code sample around this, so we get an idea on how to replace and use – Transformer Jan 05 '18 at 07:32
  • 3
    While 3ms first-run is definitely awful, would the second run be any better? If it's 3ms everytime then we'd avoid it like plague – Lionet Chen Oct 19 '20 at 01:01
  • 3
    Enum.Parse takes nanoseconds, not milliseconds, at least using modern .NET versions. I tested this code using BenchmarkDotNet in .NET 6: `MyEnum myEnum = Enum.Parse("Seven");` It produced the following result: Mean: **33.19 ns** Error: 0.469 ns StdDev: 0.392 ns – Fanblade Nov 18 '22 at 00:35
  • 2
    I also tested the speed using a variable `myString` instead of a string literal `"Seven"` to rule out special compiler optimizations when using constants. The speed results are roughly the same: `MyEnum myEnum = Enum.Parse(myString);` Mean: **42.60 ns**, Error: 0.322 ns, StdDev: 0.301 ns – Fanblade Nov 18 '22 at 16:00
  • 3
    And .NET Framework is nearly as fast as .NET 6, running the following code in **175 ns** on all .NET Framework versions 4.6.1-4.8.1: `Enum.TryParse(Input, out MyEnum result);`. This is not "awful". – Fanblade Nov 18 '22 at 18:58
130

You're looking for Enum.Parse.

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DavidWhitney
  • 4,290
  • 4
  • 24
  • 30
43

You can use extension methods now:

public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
    return (T) Enum.Parse(typeof (T), value, ignoreCase);
}

And you can call them by the below code (here, FilterType is an enum type):

FilterType filterType = type.ToEnum<FilterType>();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Foyzul Karim
  • 4,252
  • 5
  • 47
  • 70
  • 1
    I have updated this to take the value as object and cast it to string inside this method. This way I can take an int value .ToEnum instead of strings only. – RealSollyM Feb 14 '14 at 12:05
  • 2
    @SollyM I'd say that's a horrible idea cause then this extension method will apply to *all* object types. Two extension methods, one for string and one for int, would be cleaner and much safer in my opinion. – Svish Dec 09 '14 at 11:56
  • @Svish, that's true. The only reason I did this is because our code is used internally only and I wanted to avoid writing 2 extensions. And since the only time we convert to Enum is with string or int, I didn't see it being a problem otherwise. – RealSollyM Dec 10 '14 at 14:36
  • 3
    @SollyM Internal or not, I'm still the one maintaining and using my code :P I would be annoyed if I got up a ToEnum in every intellisense menu, and like you say, since the only time you convert to an enum is from string or int, you can be pretty sure you'll only need those two methods. And two methods aren't that much more than one, especially when they are this small and of the utility type :P – Svish Dec 11 '14 at 11:09
33

BEWARE:

enum Example
{
    One = 1,
    Two = 2,
    Three = 3
}

Enum.(Try)Parse() accepts multiple, comma-separated arguments, and combines them with binary 'or' |. You cannot disable this and in my opinion you almost never want it.

var x = Enum.Parse("One,Two"); // x is now Three

Even if Three was not defined, x would still get int value 3. That's even worse: Enum.Parse() can give you a value that is not even defined for the enum!

I would not want to experience the consequences of users, willingly or unwillingly, triggering this behavior.

Additionally, as mentioned by others, performance is less than ideal for large enums, namely linear in the number of possible values.

I suggest the following:

    public static bool TryParse<T>(string value, out T result)
        where T : struct
    {
        var cacheKey = "Enum_" + typeof(T).FullName;

        // [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
        // [Implementation off-topic.]
        var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);

        return enumDictionary.TryGetValue(value.Trim(), out result);
    }

    private static Dictionary<string, T> CreateEnumDictionary<T>()
    {
        return Enum.GetValues(typeof(T))
            .Cast<T>()
            .ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
    }
Timo
  • 7,992
  • 4
  • 49
  • 67
  • 6
    In fact this is very useful to know that `Enum.(Try)Parse accepts multiple, comma-separated arguments, and combines them with binary 'or'`. Means you can set up your enum values as powers of 2 and you have a very easy way to parse multiple boolean flags, eg. "UseSSL,NoRetries,Sync". In fact that's probably what it was designed for. – pcdev Aug 22 '18 at 08:00
  • @pcdev Not sure if you are aware, but this feature is to help support the (Flags attribute for enums](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum#enumeration-types-as-bit-flags). – Trisped Aug 14 '20 at 21:02
  • This one should have been the accepted answer. Major pitfall. – wenn32 Jan 19 '22 at 04:10
28

At some point a generic version of Parse was added. For me this was preferable because I didn't need to "try" to parse and I also want the result inline without generating an output variable.

ColorEnum color = Enum.Parse<ColorEnum>("blue");

MS Documentation: Parse

Jordan Ryder
  • 2,336
  • 1
  • 24
  • 29
  • 8
    Note: the generics version doesn't exist as part of .NET Framework. The equivalent syntax is `ColorEnum color = (ColorEnum)Enum.Parse(typeof(ColorEnum), "blue");`. – WSC Jun 21 '22 at 15:58
24
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

So if you had an enum named mood it would look like this:

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());
brendan
  • 29,308
  • 20
  • 68
  • 109
18

Enum.Parse is your friend:

StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tags2k
  • 82,117
  • 31
  • 79
  • 106
15

You can extend the accepted answer with a default value to avoid exceptions:

public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
    try
    {
        T enumValue;
        if (!Enum.TryParse(value, true, out enumValue))
        {
            return defaultValue;
        }
        return enumValue;
    }
    catch (Exception)
    {
        return defaultValue;
    }
}

Then you call it like:

StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);

If the default value is not an enum the Enum.TryParse would fail and throw an exception which is catched.

After years of using this function in our code on many places maybe it's good to add the information that this operation costs performance!

Nelly
  • 522
  • 6
  • 15
  • I don't like default values. It can lead to unpredictable results. – Daniël Tulp May 26 '16 at 07:46
  • 7
    when will this ever throw an exception? – andleer May 28 '16 at 15:28
  • @andleer if the enum value does not fit to the same enum type as the default value – Nelly Jan 07 '20 at 14:43
  • @Nelly Old code here but the `defaultValue` and the method return type are both of type `T`. If the types are different, you will receive a compile time error: "cannot convert from 'ConsoleApp1.Size' to 'ConsoleApp1.Color'" or whatever your types are. – andleer Jan 07 '20 at 15:33
  • @andleer, I'm sorry my last answer to you was not correct. It is possible that this method throws an Syste.ArgumentException in the case that someone calls this function with a default value that is not of type enum. With c# 7.0 I could not make a where clause of T : Enum. Thats why I catched this possibilty with a try catch. – Nelly Jan 09 '20 at 08:12
13

We couldn't assume perfectly valid input, and went with this variation of @Keith's answer:

public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
    TEnum tmp; 
    if (!Enum.TryParse<TEnum>(value, true, out tmp))
    {
        tmp = new TEnum();
    }
    return tmp;
}
gap
  • 2,766
  • 2
  • 28
  • 37
12

Most of the answers here require you to always pass in the default value of the enum each time you call on the extension method. If you don't want to go by that approach, you can implement it like below:

 public static TEnum ToEnum<TEnum>(this string value) where TEnum : struct
 {
     if (string.IsNullOrWhiteSpace(value))
          return default(TEnum);

     return Enum.TryParse(value, true, out TEnum result) ? result : default(TEnum);

 }

Using default literal (available from C# 7.1)

 public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue = default) where TEnum : struct
 {
       if (string.IsNullOrWhiteSpace(value))
            return defaultValue ;

       return Enum.TryParse(value, true, out TEnum result) ? result : defaultValue ;

 }

Better still:

public static TEnum ToEnum<TEnum>(this string value) where TEnum : struct
{
      if (string.IsNullOrWhiteSpace(value))
           return default;

      return Enum.TryParse(value, true, out TEnum result) ? result : default;

}
bkqc
  • 831
  • 6
  • 25
Bloggrammer
  • 921
  • 8
  • 21
  • On the 7.1 version, you have defined defaultValue parameter but you don't seem to use it anywhere. Is it an error or am I missing something? – bkqc Sep 23 '22 at 15:59
  • Good catch. In place of `default` you can return `defaultValue ` – Bloggrammer Sep 24 '22 at 17:26
  • But as it is, even if you call the function with a defaultValue, it will never be used since you only have `return default` and `: default`. Shouldn't it be `return defaultValue` and `: default` instead else this parameter seems to be useless and unused. Don't you get `IDE0060 - Remove unused parameter ‘defaultValue’ if it is not part of a shipped public API`? Also, as of C#7.3, you could use `where T : System.Enum` as presented here:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters#enum-constraints – bkqc Sep 26 '22 at 16:42
  • I meant `where T : struct, System.Enum` since struct is required for TryParse to work. – bkqc Sep 26 '22 at 16:50
  • Please read my previous comment very well. I said, "In place, of `default` you can return `defaultValue`". This means that; instead of `return default` you should rather have `return defaultValue`. The same is applicable in the `TryParse(...) ? result : defaultValue;` I hope that helps :) – Bloggrammer Sep 27 '22 at 12:49
8
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}
Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
8

Not sure when this was added but on the Enum class there is now a

Parse<TEnum>(stringValue)

Used like so with example in question:

var MyStatus = Enum.Parse<StatusEnum >("Active")

or ignoring casing by:

var MyStatus = Enum.Parse<StatusEnum >("active", true)

Here is the decompiled methods this uses:

    [NullableContext(0)]
    public static TEnum Parse<TEnum>([Nullable(1)] string value) where TEnum : struct
    {
      return Enum.Parse<TEnum>(value, false);
    }

    [NullableContext(0)]
    public static TEnum Parse<TEnum>([Nullable(1)] string value, bool ignoreCase) where TEnum : struct
    {
      TEnum result;
      Enum.TryParse<TEnum>(value, ignoreCase, true, out result);
      return result;
    }
JCisar
  • 2,584
  • 2
  • 29
  • 28
7

Parses string to TEnum without try/catch and without TryParse() method from .NET 4.5

/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
    enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
    if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
        return false;

    enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
    return true;
}
jite.gs
  • 71
  • 1
  • 4
  • 1
    Whether it is necessary to make a description if the code already contains a description? Ok, I did this :) – jite.gs Oct 30 '13 at 12:43
5

I like the extension method solution..

namespace System
{
    public static class StringExtensions
    {

        public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
        {
            T result;

            var isEnum = Enum.TryParse(value, out result);

            output = isEnum ? result : default(T);

            return isEnum;
        }
    }
}

Here below my implementation with tests.

using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;

private enum Countries
    {
        NorthAmerica,
        Europe,
        Rusia,
        Brasil,
        China,
        Asia,
        Australia
    }

   [TestMethod]
        public void StringExtensions_On_TryParseAsEnum()
        {
            var countryName = "Rusia";

            Countries country;
            var isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsTrue(isCountry);
            AreEqual(Countries.Rusia, country);

            countryName = "Don't exist";

            isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsFalse(isCountry);
            AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
        }
alhpe
  • 1,424
  • 18
  • 24
5

Super simple code using TryParse:

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;
Brian Rice
  • 3,107
  • 1
  • 35
  • 53
4

For performance this might help:

    private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
    public static T ToEnum<T>(this string value, T defaultValue)
    {
        var t = typeof(T);
        Dictionary<string, object> dic;
        if (!dicEnum.ContainsKey(t))
        {
            dic = new Dictionary<string, object>();
            dicEnum.Add(t, dic);
            foreach (var en in Enum.GetValues(t))
                dic.Add(en.ToString(), en);
        }
        else
            dic = dicEnum[t];
        if (!dic.ContainsKey(value))
            return defaultValue;
        else
            return (T)dic[value];
    }
Koray
  • 1,768
  • 1
  • 27
  • 37
  • 2
    You should have provided performance testing output also, like time taken to run above code when converting string to enum using your method and using regular Enum.Parse if anyone want to check about string to enum or enum to string in C#, check https://qawithexperts.com/article/c-sharp/converting-string-to-enum-or-enum-to-string-in-c/298 – Jyoti Dec 08 '20 at 15:30
3
public TEnum ToEnum<TEnum>(this string value, TEnum defaultValue){
if (string.IsNullOrEmpty(value))
    return defaultValue;

return Enum.Parse(typeof(TEnum), value, true);}
AHMED RABEE
  • 467
  • 6
  • 13
3

If the property name is different from what you want to call it (i.e. language differences) you can do like this:

MyType.cs

using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

[JsonConverter(typeof(StringEnumConverter))]
public enum MyType
{
    [EnumMember(Value = "person")]
    Person,
    [EnumMember(Value = "annan_deltagare")]
    OtherPerson,
    [EnumMember(Value = "regel")]
    Rule,
}

EnumExtensions.cs

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

public static class EnumExtensions
{
    public static TEnum ToEnum<TEnum>(this string value) where TEnum : Enum
    {
        var jsonString = $"'{value.ToLower()}'";
        return JsonConvert.DeserializeObject<TEnum>(jsonString, new StringEnumConverter());
    }

    public static bool EqualsTo<TEnum>(this string strA, TEnum enumB) where TEnum : Enum
    {
        TEnum enumA;
        try
        {
            enumA = strA.ToEnum<TEnum>();
        }
        catch
        {
            return false;
        }
        return enumA.Equals(enumB);
    }
}

Program.cs

public class Program
{
    static public void Main(String[] args) 
    { 
        var myString = "annan_deltagare";
        var myType = myString.ToEnum<MyType>();
        var isEqual = myString.EqualsTo(MyType.OtherPerson);
        //Output: true
    }     
}
Joel Wiklund
  • 1,697
  • 2
  • 18
  • 24
2

I used class (strongly-typed version of Enum with parsing and performance improvements). I found it on GitHub, and it should work for .NET 3.5 too. It has some memory overhead since it buffers a dictionary.

StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");

The blogpost is Enums – Better syntax, improved performance and TryParse in NET 3.5.

And code: https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Patrik Lindström
  • 1,057
  • 3
  • 13
  • 23
2
public static T ParseEnum<T>(string value)            //function declaration  
{
    return (T) Enum.Parse(typeof(T), value);
}

Importance imp = EnumUtil.ParseEnum<Importance>("Active");   //function call

====================A Complete Program====================

using System;

class Program
{
    enum PetType
    {
    None,
    Cat = 1,
    Dog = 2
    }

    static void Main()
    {

    // Possible user input:
    string value = "Dog";

    // Try to convert the string to an enum:
    PetType pet = (PetType)Enum.Parse(typeof(PetType), value);

    // See if the conversion succeeded:
    if (pet == PetType.Dog)
    {
        Console.WriteLine("Equals dog.");
    }
    }
}
-------------
Output

Equals dog.
Rae Lee
  • 1,321
  • 10
  • 11
2

I found that here the case with enum values that have EnumMember value was not considered. So here we go:

using System.Runtime.Serialization;

public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    TEnum result;
    var enumType = typeof(TEnum);
    foreach (var enumName in Enum.GetNames(enumType))
    {
        var fieldInfo = enumType.GetField(enumName);
        var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
        if (enumMemberAttribute?.Value == value)
        {
            return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
        }
    }

    return Enum.TryParse(value, true, out result) ? result : defaultValue;
}

And example of that enum:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}
isxaker
  • 8,446
  • 12
  • 60
  • 87
2

You have to use Enum.Parse to get the object value from Enum, after that you have to change the object value to specific enum value. Casting to enum value can be do by using Convert.ChangeType. Please have a look on following code snippet

public T ConvertStringValueToEnum<T>(string valueToParse){
    return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}
Bartosz Gawron
  • 189
  • 1
  • 8
2

Try this sample:

 public static T GetEnum<T>(string model)
    {
        var newModel = GetStringForEnum(model);

        if (!Enum.IsDefined(typeof(T), newModel))
        {
            return (T)Enum.Parse(typeof(T), "None", true);
        }

        return (T)Enum.Parse(typeof(T), newModel.Result, true);
    }

    private static Task<string> GetStringForEnum(string model)
    {
        return Task.Run(() =>
        {
            Regex rgx = new Regex("[^a-zA-Z0-9 -]");
            var nonAlphanumericData = rgx.Matches(model);
            if (nonAlphanumericData.Count < 1)
            {
                return model;
            }
            foreach (var item in nonAlphanumericData)
            {
                model = model.Replace((string)item, "");
            }
            return model;
        });
    }

In this sample you can send every string, and set your Enum. If your Enum had data that you wanted, return that as your Enum type.

user229044
  • 232,980
  • 40
  • 330
  • 338
AmirReza-Farahlagha
  • 1,204
  • 14
  • 26
  • 2
    You are overwriting `newModel` on each line, so if it contains dashes, it will not be replaced. Also, you don't have to check if the string contains anything, you can just call `Replace` anyway: `var newModel = model.Replace("-", "").Replace(" ", "");` – Lars Kristensen Oct 01 '18 at 09:52
  • 1
    @LarsKristensen Yeah we can create an method that remove nonalphanumeric character. – AmirReza-Farahlagha Oct 01 '18 at 09:56
1
        <Extension()>
    Public Function ToEnum(Of TEnum)(ByVal value As String, ByVal defaultValue As TEnum) As TEnum
        If String.IsNullOrEmpty(value) Then
            Return defaultValue
        End If

        Return [Enum].Parse(GetType(TEnum), value, True)
    End Function
AHMED RABEE
  • 467
  • 6
  • 13
1

If you want to use a default value when null or empty (e.g. when retrieving from config file and the value does not exist) and throw an exception when the string or number does not match any of the enum values. Beware of caveat in Timo's answer though (https://stackoverflow.com/a/34267134/2454604).

    public static T ParseEnum<T>(this string s, T defaultValue, bool ignoreCase = false) 
        where T : struct, IComparable, IConvertible, IFormattable//If C# >=7.3: struct, System.Enum 
    {
        if ((s?.Length ?? 0) == 0)
        {
            return defaultValue;
        }

        var valid = Enum.TryParse<T>(s, ignoreCase, out T res);

        if (!valid || !Enum.IsDefined(typeof(T), res))
        {
            throw new InvalidOperationException(
                $"'{s}' is not a valid value of enum '{typeof(T).FullName}'!");
        }
        return res;
    }
MBWise
  • 700
  • 1
  • 8
  • 17
0

I started to use this approach. Performance seems to be ok however it requires a bit of boilerplate code setup.

public enum StatusType {
    Success,
    Pending,
    Rejected
}

static class StatusTypeMethods {

    public static StatusType GetEnum(string type) {
        switch (type) {
            case nameof(StatusType.Success): return StatusType.Success;
            case nameof(StatusType.Pending): return StatusType.Pending;
            case nameof(StatusType.Rejected): return StatusType.Rejected;
            default:
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
        };
    }
}

And later on, you can use it like this:

StatusType = StatusType.GetEnum("Success");
Jared_M
  • 547
  • 1
  • 5
  • 13
-1

First of all, you need to decorate your enum, like this:

    public enum Store : short
{
    [Description("Rio Big Store")]
    Rio = 1
}

in .net 5, i create this extension method:

//The class also needs to be static, ok?
public static string GetDescription(this System.Enum enumValue)
    {
        FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());

        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
            typeof(DescriptionAttribute), false);

        if (attributes != null && attributes.Length > 0) return attributes[0].Description;
        else return enumValue.ToString();
    }

now you have an extension methods to use in any Enums

Like this:

var Desc = Store.Rio.GetDescription(); //Store is your Enum
Felipe Augusto
  • 1,341
  • 1
  • 16
  • 18