16

There's lots of questions on here about converting strings to an enum value. Generally, the answer looks something like the answers on this question:

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

While that's a perfectly reasonable answer, and you can write a method to simplify the call, it doesn't answer the question of why Enum.Parse() returns an object instead of the appropriate enum value. Why do I have to cast it to StatusEnum?


Edit:

Basically, the question is why is a function like this not part of the Enum class?

    public static T Parse<T>(string value) where T: struct 
    {
        return (T)Enum.Parse(typeof (T), value);
    }

This function works perfectly fine, does exactly what you'd expect. StatusEnum e = Enum.Parse<StatusEnum>("Active");.

Community
  • 1
  • 1
Bobson
  • 13,498
  • 5
  • 55
  • 80
  • 1
    @SpYk3HH - Enums don't *have* values. They *are* values. They're values that happen to have an usual overload for `.ToString()`, but they're still just values. – Bobson Sep 07 '12 at 20:31
  • 2
    .NET 4.0+ has [`Enum.TryParse`](http://msdn.microsoft.com/en-us/library/dd783499(v=vs.100)) – Paolo Moretti Sep 07 '12 at 20:36
  • @SpYk3HH a value of an enum type is some integer that may be associated with one of the enum type's fields. The size of the integer may vary. Parse takes some string and returns a boxed instance of the enum type. That can be unboxed or not. Your last sentence also makes no sense. String and Boolean also have properties and methods upon which to work. – phoog Sep 07 '12 at 20:38
  • @SpYk3HH in the .NET framework, parse means "take this string and give me the associated value of the type in question". – phoog Sep 07 '12 at 20:39
  • @SpYk3HH - I think you're missing the point. The line of code above returns a specific value. It doesn't return a collection of values. It doesn't return all possible values of that enum. It returns a single specific value: `StatusEnum.Active`. There's nothing I can do with that value as an `object` that I couldn't do better with it as a `StatusEnum`. – Bobson Sep 07 '12 at 20:40
  • @PaoloMoretti - That's true, but it returns a bool. So it just makes the lack of `Enum.Parse` even more confusing. – Bobson Sep 07 '12 at 20:41
  • In your second example, you're using var. Couldn't you do the same thing with your first example: var MyStatus = Enum.Parse(typeof(StatusEnum), "Active", true); – Slapout Sep 07 '12 at 20:54
  • @Slapout - Yes, but `var` would be of type `object` then. Still, I'll edit the question to make it a non-issue. – Bobson Sep 07 '12 at 20:56
  • 1
    @Slapout - Which is `object` if not cast, since `Enum.Parse()` returns `object`. – Bobson Sep 07 '12 at 21:14

5 Answers5

12

It does this because

  1. It predated generics and (even if it hadn't:)
  2. Generic constraints can't be enums (in the mainstream .NET languages)

As such, Object is the only type that will always work for any type of enum.

By returning object, the API is at least functional, even if a cast is required.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 1
    While you can't say `where t : Enum` you can say `where t : struct` and at least eliminate reference types, or put no constraint and avoid the cast/typeof. – Guvante Sep 07 '12 at 20:28
  • The fact that it predated generics is not an explination. It would be a non-breaking change to add the function I edited in above as an overload for the old-style `Enum.Parse()`. – Bobson Sep 07 '12 at 20:42
  • @Reed - Come to think of it, by your logic, Enum.TryParse() shouldn't exist either, but it does. – Bobson Sep 07 '12 at 20:59
  • "2. Generic constraints can't be enums" isn't true, as far as the CIL is concerned, you just can't write it in C#: http://msmvps.com/blogs/jon_skeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx – Tim S. Sep 07 '12 at 21:14
  • @TimS. Yes - but you can't do it in any of the mainstream CLR languages – Reed Copsey Sep 07 '12 at 22:41
  • I suppose this is the best answer to the original question, even though it doesn't address the edit. I may open a new question for that. – Bobson Oct 25 '12 at 19:17
4

TryParse does however support a type parameter:

Enum.TryParse<FooEnum>(name, true, out ret);

Therefore, if you specify the out value ret as FooEnum ret;, you won't need to cast it to a FooEnum afterwards; it'll be of the proper type right away.

aevitas
  • 3,753
  • 2
  • 28
  • 39
  • It's true, but you now need two lines of code. Possibly three. One to declare `ret`, this one, and one to use it which you might not otherwise have needed. Thus raising the question of why there's a generic form of `TryParse()` and not a generic form of `Parse()`. – Bobson Sep 07 '12 at 21:13
  • It's probably just overlooked. You could make your own generic overload as an extension method quite easily though. – aevitas Sep 07 '12 at 21:30
  • Actually, you can't. You can't extend `Enum`, because it's a static class. So you'd be calling `EnumExtensions.Parse()` (or whatever you called your class), and there would be no benefit to being an extension method. – Bobson Sep 07 '12 at 21:36
3

The actual type of the object is indeed StatusEnum. The compiler, and the code, when writing Enum.Parse has no idea what that runtime object will be at the time the method is written. It won't be known until the method is actually called.

Servy
  • 202,030
  • 26
  • 332
  • 449
1

.NET Core 2.0-3.1 and .NET 5 both support Enum.Parse like you want it

DudeWhoWantsToLearn
  • 751
  • 2
  • 10
  • 29
0

A solution could be to use a static extension method.

public static class StringExtensions
{
    public static T ParseEnum<T>(this string t) where T: struct 
    {
        return (T)Enum.Parse(typeof (T), t);
    }
}

...

var EnumValue = "StringValue".ParseEnum<MyEnum>();
Arturo Hernandez
  • 2,749
  • 3
  • 28
  • 36