type-casting System.Array of Enum values fails to "box"/convert correctly

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Plater
    Recognized Expert Expert
    • Apr 2007
    • 7872

    type-casting System.Array of Enum values fails to "box"/convert correctly

    I ran into this interesting little issue when make a settings window for a SerialPort.

    I have the following enum:
    [code=c#]
    public enum BaudRates : int
    {
    BR1200 = 1200,
    BR2400 = 2400,
    BR4800 = 4800,
    BR9600 = 9600,
    BR19200 = 19200,
    BR3800 = 38400,
    BR57600 = 57600,
    BR115200 = 115200,
    BR230400 = 230400,
    }
    [/code]

    I use the Enum class to retreive an array collection
    [code=c#]
    Array BRs = Enum.GetValues( typeof(BaudRate s));
    [/code]

    Now the thought is that I roughly have a BaudRate[] (instead of just returning an Object, they return an Array which all <type>[] inherit from?)
    So I figure since my ENUM type is also an int, I'll do this:
    [code=c#]
    int[] intBRs (int[])BRs;
    [/code]
    I was actually surprised it compiled and executed.
    intBRs is now usable like a regular int[].
    Here is where the confusion comes in. intBRs.GetType( ) shows type of BaudRate[] and not int[] as it was declared.
    Looking at the debug window, it shows BR1200 BR2400 and etc anstead of 1200,2400, etc.
    BUT I can say int a= intBRs[0]; and a has the value of 1200 just fine.

    Now I know there is implicit conversion involved, but I want to use the intBRs as the datasource for a ComboBox and then set the SelectedItem to mySerialPort.Ba udRate.
    It cannot do this since the datasource is using BR1200, BR2400.
    I can get around it by typecasting mySerialPort.Ba udRate as a BaudRates, but I think the intBRs should have really been a int[] not a BaudRates[];

    Work around:
    [code=C#]
    int[] intBRs = (int[])Enum.GetValues (typeof(BaudRat es));
    cbBaudRate.Data Source = (int[])intBRs;
    cbBaudRate.Sele ctedItem = (BaudRates)_por t.BaudRate;
    [/code]
    This has the effect of the listbox showing the ENUM names and not the values, which is a bit more confusing when looking at the choices in the listbox

    Does anyone have any thoughts on the boxing/unboxing issues
  • Curtis Rutland
    Recognized Expert Specialist
    • Apr 2008
    • 3264

    #2
    I think you'll just have to do the typecasting. According to the examples of Enum.GetValues, I thought you were right at first. But they explicitly type the iteration variable in the foreach. I did this:

    Code:
    Console.WriteLine("Implicit:");
    foreach(var v in Enum.GetValues(typeof(BaudRates)))
        Console.WriteLine(v);
    Console.WriteLine("\nExplicit:");
    foreach(int i in Enum.GetValues(typeof(BaudRates)))
        Console.WriteLine(i);
    And got this result:

    Implicit:
    BR1200
    BR2400
    BR4800
    BR9600
    BR19200
    BR3800
    BR57600
    BR115200
    BR230400

    Explicit:
    1200
    2400
    4800
    9600
    19200
    38400
    57600
    115200
    230400
    It appears that this is expected behavior.

    If you are a LINQ kinda guy, there's another syntax for the cast:

    Code:
    var intBRs = Enum.GetValues(typeof(BaudRates)).Cast<int>().ToList();

    Comment

    • Plater
      Recognized Expert Expert
      • Apr 2007
      • 7872

      #3
      I am bothered by int[] intBRs not producing an int[].
      I figured if it was going to ignore my requested type, I could do something like:
      [code=c#]
      int[] test1 = ((int[])Enum.GetValues (typeof(BaudRat es)));
      float[] test2 = ((float[])Enum.GetValues (typeof(BaudRat es)));
      [/code]
      test1 creates that an object of type BaudRates[] and test2 throws an exception, cannot cast BaudRate[] to float[]...which means it IS trying to do casting and KNOWS that the BaudRate is also an int. Rather annoying.
      I changed that enum to be :ulong and test1 failed up above, but another test using ulong[] worked the same way as int[] did previously.
      I really think that is incorrect behavior. It tries to validate the type, but doesn't actually do the cast.

      Comment

      • Curtis Rutland
        Recognized Expert Specialist
        • Apr 2008
        • 3264

        #4
        Ok, I see what I missed the first time.

        Code:
        Array vals = Enum.GetValues(typeof(BaudRates));
        int[] ints = (int[])vals;
        Console.WriteLine("vals.GetType(): {0}", vals.GetType());
        Console.WriteLine("ints.GetType(): {0}", ints.GetType());
        Console.WriteLine("Print all vals:");
        foreach (var i in ints)
            Console.WriteLine(i);
        Console.WriteLine("Print all ints:");
        foreach (var v in vals)
            Console.WriteLine(v);
        vals.GetType(): HelloWorld.Baud Rates[]
        ints.GetType(): HelloWorld.Baud Rates[]
        Print all vals:
        1200
        2400
        4800
        9600
        19200
        38400
        57600
        115200
        230400
        Print all ints:
        BR1200
        BR2400
        BR4800
        BR9600
        BR19200
        BR3800
        BR57600
        BR115200
        BR230400
        Interesting. Apparently, casting the array didn't actually convert the values, it just boxes the array itself. So when you get a value via the the array, it implicitly casts it to the array type, but it's still stored as the original type.

        Apparently that's the way arrays work. You're not performing a cast on each object, just the array object itself.

        The Cast<T>() method I showed will actually cast each element, if you want to use that. Other than that, I'm not sure.

        Comment

        • Plater
          Recognized Expert Expert
          • Apr 2007
          • 7872

          #5
          I guess I need to move up in the .NET versions. .NET2.0 doesn't support using var or any of the linq stuff.
          So i used object instead of var. Interesting, I got your results.
          It must be that when I assigned it as the datasource, it lost its int[] boxing and just interpreted the BR1200 values. Still odd.

          Comment

          • Curtis Rutland
            Recognized Expert Specialist
            • Apr 2008
            • 3264

            #6
            Yeah, I don't know what I'd do without LINQ. Go crazy, probably. Var is usually just me being lazy, but when you use anonymous types, it's the only way to declare them.

            Comment

            Working...