1

I've searched and tried many things but I'm not really fully happy.

While converting an old project from VB.Net to C# I found that the behaviour between the 2 languages is very different and breaks the logic in C# if not dealt with.

Consider an enum like:

public enum TestEnum
{
    Val1 = 1,
    Val2 = 2
}

I have this code in VB.Net

// Will contain 1
txthMyHiddenField.Value = TestEnum1.Val1 

And also

// Will contain ~/Something?var=1
Dim Url As String = "~/Something?var=" & TestEnum1.Val1

In C# this would have the first case having Val1 and on the second case "~/Something?var=Val1"

The solution so far I could come up with without redesigning lots of code is to go everywhere and do something like:

= myEnum.ToString("d");

// Or

= ((int)myEnum).ToString();

// Or an extension.

I also considered creating an enum "class" but then I would have to change all switch statements, which is an even worse solution.

Am I missing something? Is there a cleaner way?

  • 1
    I like the idea of adding an extension method if you need this a lot. Otherwise I would just cast to an int – TGH Oct 21 '13 at 21:20
  • What exactly is the problem? when the value is parsed back from its string representation to the enum, either a numeric value or the enum value's name is perfectly acceptable. – Nicholas Carey Oct 21 '13 at 21:21
  • possible duplicate of [Get int value from enum](http://stackoverflow.com/questions/943398/get-int-value-from-enum) – Tommy Grovnes Oct 21 '13 at 21:22
  • @NicholasCarey not really, the use of enums in my case are not to be parsed ever but to be treated like ints all the time. The point is the ints will never change but the name of the enum might when refactoring –  Oct 21 '13 at 21:27
  • _Am I missing something?_ No, apparently not. _Is there a cleaner way?_ No. You mentioned `.ToString("d")` and cast to `int` yourself, and you mentioned creating an extension method. Those are the natural options. Enjoy. – Jeppe Stig Nielsen Oct 21 '13 at 21:32
  • You can also use this `d` in a `string.Format`, as in `string url = string.Format("~/Something?var={0:d}", myEnum);`. – Jeppe Stig Nielsen Oct 21 '13 at 21:44

2 Answers2

5

Why not simply

var url = "~/Somethimg?var=" + (int)myEnum;

For what it's worth, maybe this extension helps:

public static class EnumExtensions
{ 
    public static int AsInt<TEnum>(this TEnum enumType) where TEnum : struct, IConvertible
    {
        if (!typeof(TEnum).IsEnum)
            throw new ArgumentException("TEnum must be an enum type");
        return ((IConvertible)enumType).ToInt32(null);
    }
}

var url = "~/Somethimg?var=" + myEnum.AsInt();
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • It breaks other code like "string myStr = (int)myEnum" which would have to be converted to "string myStr = ((int)myEnum).ToString()" –  Oct 21 '13 at 21:22
  • Well (int)myEnum isn't a string. So you use ToString on it. "a string" + (int)myEnum works because the + sign calls myEnum.ToString() automatically. – Measurity Oct 21 '13 at 21:26
  • The ToString on an enum gets the string name of the enum, not the int value of the enum, thus you have to convert to int and then to string –  Oct 21 '13 at 21:27
  • @Rivers, To Clarify...You have vb.net code that relies on one behavior (ex: concat an int as in your example), and code written in C# that relies on the alternate behavior - (string value "Val1", etc)? If there isn't an all encompassing solution (ie: just get the int value every time), then it may be helpful to list all of the potential desired behaviors that the code base needs to cover. – JFish222 Oct 21 '13 at 21:28
  • 2
    That's just one of the differences between c# and VB, VB guesses what you want in those situations and usually gets it right but if it doesn't is a pain. C# makes you spell it out. – Eric Oct 21 '13 at 21:29
  • @Rivers: I don't see how the code above breaks other code since it's a different situation. However, you could create an extension. Edited my answer. – Tim Schmelter Oct 21 '13 at 21:31
  • Your missing the whole point of my question and thats perhaps my fault, I will try to clarify my question so that it's easily understandable –  Oct 21 '13 at 21:33
  • If you want to be fancy (support enum with underlying type `long`), you can do `Convert.ChangeType(enumType, Enum.GetUnderlyingType(typeof(TEnum))).ToString()`. It is ugly and uses boxing. – Jeppe Stig Nielsen Oct 21 '13 at 21:38
  • @Eric yes it's because I love C# and the strongly typed concept that I've urged to change it to C#. I Pointed out 4 examples to fix my case, just hoping to see if this is really the only way to go –  Oct 21 '13 at 21:39
  • 1
    @Rivers: VB.NET is also strongly typed if you set Option Strict to `on` what is recommended. – Tim Schmelter Oct 21 '13 at 21:41
  • It can be, but the default is Off and it wasn't in this case. –  Oct 21 '13 at 21:42
  • @Rivers: The first thing to do: change VB default to use `OPTION STRICT On`, always. I've been programming with VB.NET since 2002 and have never used off. – Tim Schmelter Oct 21 '13 at 21:47
  • It's not your place yo criticize if the setting should be on or off, I've been a developer longer than that and in this case when converting the application from VB6 to VB.Net it was a natural decision. –  Oct 21 '13 at 21:58
  • @Rivers: It was no critic just a recommendation and not even addressed to you exclusively. – Tim Schmelter Oct 21 '13 at 22:08
1

@Rivers,

I added a comment requesting more info in @Tim Schmelter's post but will try to provide a solution in the mean time.

@Eric, is correct in that it appears to come down to the explicit nature of C#. I also agree with @THG that if there is any change of repeatedly requiring this conversion, then an extension method is the cleanest way to go.

I haven't found a way to explicitly filter for enum, so I would be very interested in how such an extension method could be implemented.

In my case, I have limited type filtering and perform runtime validation. (I would obviously prefer compile time):

public static string ToIntString<T>(this T enumVal) where T : struct, IConvertible, IComparable, IFormattable
{
   TestGenericEnum<T>();
   return (Convert.ToInt32(enumVal).ToString();
}

private static void TestGenericEnum<T>()
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("T must be of type System.Enum");
}

Update: Tossed in IComparable, IFormattable restrictions per @Preston's advice.
Update 2: Bone headed move, can't cast int directly, need to use Convert class.

JFish222
  • 1,026
  • 7
  • 11
  • I had to laugh when I read the name of your extension (that was my first name too) :) –  Oct 21 '13 at 21:45
  • I had to accept this answer just because it is the one who understands the fact that what I wanted was to findout if there was another cleaner way of getting the int value of an enum as a string. –  Oct 21 '13 at 21:50
  • 1
    There isn't any way of constraining solely to enum, but `where T: struct, IConvertible, IComparable, IFormattable` is more constrained than what you have here and still matches enums. Moons ago @jon-skeet wrote UnconstraintedMelody (http://msmvps.com/blogs/jon_skeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx) for this kind of thing, but it requires a bit of hoop jumping, and I'm not sure if it's been maintained. – Preston Guillot Oct 21 '13 at 21:59
  • Thank you Rivers, but I have to give Tim a tick for speed...even if his method name wasn't as cool as mine! :) @Preston, fantastic! Thank for that article and tip. I'll update my response, and check out that article asap. – JFish222 Oct 21 '13 at 22:05
  • His method converts to int when I need a string containing the int value of an enum. I have updated my extension with your constraints, much appreciated. –  Oct 21 '13 at 22:09