3

I have a property of type object, which contains an Enum value, and when I cast it using (int)value, it returns a string of the Enum's name. Why?

The code where I noticed this is in this answer. Using Convert.ToInt32() correctly casts the Enum to an int, but I was just curious why I would get a string back when using (int). It doesn't even throw me an error.

Edit

Here's a quick sample. I commented where I put the breakpoint, and was using the immediate window to determine what the output was.

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public Int32 SomeNumber { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        SomeNumber = 1;
        RootWindow.DataContext = this;

    }
}

public enum MyEnum
{
    Value1 = 1,
    Value2 = 2,
    Value3 = 3
}


/// <summary>
/// Returns true if the int value equals the Enum parameter, otherwise returns false
/// </summary>
public class IsIntEqualEnumParameterConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (parameter == null || value == null) return false;

        if (parameter.GetType().IsEnum && value is int)
        {
            // Breakpoint here
            return (int)parameter == (int)value;
        }
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

MainWindow.xaml

<Window x:Class="WpfApplication5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication5"
        Title="MainWindow" Height="350" Width="525"
        x:Name="RootWindow">

    <Window.Resources>
        <local:IsIntEqualEnumParameterConverter x:Key="IsIntEqualEnumParameterConverter" />
    </Window.Resources>

    <StackPanel>
        <TextBlock Text="{Binding SomeNumber, Converter={StaticResource IsIntEqualEnumParameterConverter}, ConverterParameter={x:Static local:MyEnum.Value1}}" />
    </StackPanel>
</Window>

Edit #2

Just hoping to clear up some confusion...

I said it was returning a string because running ?((int)parameter) in the Immediate Window was returning the enum name, while running ?System.Convert.ToInt32(parameter) was correctly displaying the int.

I found afterwards that it was actually evaluating correctly to the DataTrigger all along. I thought it wasn't because my control wasn't visible at runtime, however I discovered that was because of an error in my XAML (I forgot a Grid.Column property, so one control was overlapping another).

Sorry for the confusing question.

Edit #3

Here's some console app code demonstrating the situation just for Jon :)

class Program
{
    static void Main(string[] args)
    {
        object value;
        value = Test.Value1;

        // Put breakpoint here
        // Run ?(int)value vs Convert.ToInt32(value) in the immediate window
        // Why does the first return Value1 while the 2nd returns 1?
        Console.ReadLine();
    }
}

public enum Test
{ 
    Value1 = 1
}
Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Can you paste a working example of the code? – Leslie Hanks Aug 18 '11 at 18:00
  • 1
    Are you putting it into a string? Are you casting it in a Console.WriteLine()? I'm not seeing the same issue. Casting it to an int seems to give me the expected behavior. – John Kraft Aug 18 '11 at 18:02
  • Something else is going on. `object o = MyEnum.Blah; int i = (int)o;` sets `i` to the integer value of the enumeration member. – dlev Aug 18 '11 at 18:03
  • 3
    That ain't possible. You can't direct cast and get something of a different type. –  Aug 18 '11 at 18:03
  • Yep, add a snippet of code showing the source for "parameter" so we can better evaluate what is going on. It's probably something fairly straightforward, but without an example of the call, we cannot see. – James Michael Hare Aug 18 '11 at 18:04
  • @Leslie Sure, code added. It's a WPF Converter – Rachel Aug 18 '11 at 18:05
  • The behavior was noticed by putting a breakpoint there and running `(int)parameter` in the immediate window – Rachel Aug 18 '11 at 18:05
  • @Rachel: we see the code of your converter, but need to see the call to that code itself if possible. – James Michael Hare Aug 18 '11 at 18:06
  • 1
    @Rachel That will just show the value of the expression in text form; the expression itself isn't a string, though. – dlev Aug 18 '11 at 18:06
  • If that were to evaluate to a string, how would the cast even work? You'd get an InvalidCastException, no? – BoltClock Aug 18 '11 at 18:06
  • Do you mean if you check `parameter is int` at the immediate window it will return `false` then? – Jalal Said Aug 18 '11 at 18:07
  • @Rachel: BTW, to your other point, Convert.ToInt32() will work on a string representation of an enum because string and enum both implement IConvertible and it's a conversion, not a cast. (int) is a cast (when performed from object) not a conversion, so if the object is not an int, you should throw an InvalidCastException. – James Michael Hare Aug 18 '11 at 18:07
  • 2
    Please paste a copy of what you're seeing in the Immediate Window. – Jon Skeet Aug 18 '11 at 18:09
  • Could you post an example of the code that's giving you this problem? Once you cast to int, it will stay int, so I suspect something else is going on here. (Most likely, the type of the variable you're displaying is an Enum. When you display an Enum via ToString() or similar if the variable holds a defined value from the enumeration the name is displayed instead of the numeric value.) – Chris Phillips Aug 18 '11 at 18:10
  • 1
    I've just tried Rachel's console code, and got the same result. Interestingly, if you change the type of `value` to `Test`, it shows 1 instead... – Jon Skeet Aug 18 '11 at 19:23
  • @Jon I noticed that too... no clue why. Perhaps it's just a VS bug. – Rachel Aug 18 '11 at 19:29
  • @Rachel: Sounds like it. I suggest you report it on connect.microsoft.com. – Jon Skeet Aug 18 '11 at 19:30

5 Answers5

11

It sounds like you're being duped by the Immediate Window. It's not clear exactly what you did in the Immediate Window, but I can say with absolute certainty that if you cast to an int you do not get a string back. The type system completely prevents that from happening.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • You are correct, the value is correct in the output, just not in the immediate window. Good to know that I shouldn't blindly trust the immediate window. (I had an error in my XAML which was making me think the converter was always returning false since a control was not visible) – Rachel Aug 18 '11 at 18:14
  • And I was writing `?((int)parameter)` in the Immediate window and it was returning `Value1`. Running `?System.Convert.ToInt32(parameter)` was correctly returning `1` – Rachel Aug 18 '11 at 18:31
  • @Rachel: Hmm... can't even reproduce that. But I very rarely use the Immediate Window to start with :) – Jon Skeet Aug 18 '11 at 18:37
  • Strange, I double-checked by pulling out the relevant code and putting it in its own application, and the same thing occurs. I posted the code I used in my sample if you want to try. I'm using VS2010 Ultimate, SP1, AsyncCTP Refresh, and no mods. – Rachel Aug 18 '11 at 18:56
  • @Rachel: I'll give it a try later on. If you see it in a console app as well, it could be even simpler :) If I can reproduce it more simply, I'll post that code here. – Jon Skeet Aug 18 '11 at 18:57
  • Sure, I did a quick check and it does the same thing with a console app. Added a trimmed down version of the code to the question. I'd love to know why it's returning the enum name instead of the int value. – Rachel Aug 18 '11 at 19:08
  • @Rachel: Thanks - it makes a *huge* difference to me to be able to do everything in just one file, nothing in the designer, nothing messy... – Jon Skeet Aug 18 '11 at 19:11
1

It's technically impossible what you describe here. What you see is the NAME of enumeration member which is shown by debugger. Think of this like kind of "syntax sugare". So the real problem IMHO, is that just to ints are not equal.

To check this:

Read your "string", Check integer assigned to in enumeration declared, and ceck if integer actually equals to that one you get like a parameter in the function.

Tigran
  • 61,654
  • 8
  • 86
  • 123
1

Your question is really "why" and not "how", I realize that.

However, here's how:

enum Options : int { one = 1, two = 2, three = 3 }
public MainWindow()
{
    InitializeComponent();

    object _Option = Options.three;

    // shows "three"
    MyTextBox.Text = ((Options)_Option).ToString();

    // shows "3"
    MyTextBox.Text = ((int)((Options)_Option)).ToString();
}
Jerry Nixon
  • 31,313
  • 14
  • 117
  • 233
0

I've run this code sample into oblivion, and I'm finding it to return false each time because the value is int is failing. value is an object, not an integer.

John Kraft
  • 6,811
  • 4
  • 37
  • 53
0

I imagine what is happening is that your object parameter is coming in as a string value and thus your call to

 if (parameter.GetType().IsEnum && value is int)

is false and you skip the body and return false directly.

Instead, use Enum.Parse() or Convert.ToInt32() to change the string into either the enum value or the int value and then compare.

James Michael Hare
  • 37,767
  • 9
  • 73
  • 83