12

In C#, if we define an enum that contains a member correspondingto a negative value, and then we iterate over that enum's values, the negative value does not come first, but last. Why does that happen? In other languages (C, C++, Ada, etc), iterating over an enum will give you the order in which you defined it.

MSDN has a good example of this behavior:

using System;

enum SignMagnitude { Negative = -1, Zero = 0, Positive = 1 };

public class Example
{
    public static void Main()
    {
        foreach (var value in Enum.GetValues(typeof(SignMagnitude)))
        {
            Console.WriteLine("{0,3}     0x{0:X8}     {1}",
                              (int) value, ((SignMagnitude) value));
        }   
    }
}

// The example displays the following output: 
//         0     0x00000000     Zero 
//         1     0x00000001     Positive 
//        -1     0xFFFFFFFF     Negative
stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
gmletzkojr
  • 385
  • 3
  • 11
  • 2
    It's probably being sorted as unsigned. – SLaks Aug 09 '13 at 14:11
  • 4
    You made it [*one* step further than many programmers](http://stackoverflow.com/questions/18095665/a-lambda-expression-with-a-statement-body-cannot-be-converted-to-an-expression-t/18095816#comment26488750_18095816) by making to the documentation. Next time, read it: "The elements of the array are sorted by the binary values of the enumeration constants (**that is, by their unsigned magnitude**)." – jason Aug 09 '13 at 14:14
  • From the same [MSDN](http://msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx) article: "The elements of the array are sorted by the binary values of the enumeration constants (that is, by their unsigned magnitude)." – natenho Aug 09 '13 at 14:14
  • I wodner if the order in which `enum`s are declared does not matter and is not preserved? – John Alexiou Aug 09 '13 at 14:14
  • http://stackoverflow.com/a/6819456/330606 –  Aug 09 '13 at 14:15
  • Thanks @Jason. You've attempted to insult me, and that poor fellow in your linked answer again. It seems that even though I scanned over the documentation, I missed the line about enums being stored as unsigned values. You must be awesome to work with. – gmletzkojr Aug 09 '13 at 14:56
  • 1
    @gmletzkojr: I did *not* attempt to insult you. In fact, I *commended* you for at least checking the documentation and then I made a blunt statement of advice that could have kept you from wasting your own time. I'm *genuinely* sorry you feel insulted, my comment was most definitely blunt, but it was *not* my intention. – jason Aug 09 '13 at 15:51
  • possible duplicate of [Enum.GetNames() results in unexpected order with negative enum constants](http://stackoverflow.com/questions/6819348/enum-getnames-results-in-unexpected-order-with-negative-enum-constants) – Jeremy Aug 09 '13 at 15:59

1 Answers1

16

From the very documentation page you link to, my emphasis:

The elements of the array are sorted by the binary values of the enumeration constants (that is, by their unsigned magnitude).

Digging into the CLR code (the 2.0 SSCLI) and getting far lower-level than I'm really comfortable with, it looks like ultimately this is because internally enum values are stored in something that looks like this (note this is C++):

class EnumEEClass : public EEClass
{
    friend class EEClass;

 private:

    DWORD           m_countPlusOne; // biased by 1 so zero can be used as uninit flag
    union
    {
        void        *m_values;
        BYTE        *m_byteValues;
        USHORT      *m_shortValues;
        UINT        *m_intValues;
        UINT64      *m_longValues;
    };
    LPCUTF8         *m_names;

As can be seen, it's unsigned types that hold the actual values - so when these values are emitted for enumeration, naturally they are in their unsigned order.

AakashM
  • 62,551
  • 17
  • 151
  • 186
  • 8
    Interestingly, this started off as a bug (http://connect.microsoft.com/VisualStudio/feedback/details/98147/enum-getvalues). If you look at earlier versions of the documentation before 3.5 there's no official mention that it used their unsigned magnitude. Due to the inability to fix it without breaking existing applications, I guess they just updated the docs :D – keyboardP Aug 09 '13 at 14:14
  • 1
    Thanks @keyboardP, that's what I was really asking. – gmletzkojr Aug 09 '13 at 14:18
  • 1
    Good answer. However, it assumes that the reader know how negative numbers are represented (factually [two's complement](http://en.wikipedia.org/wiki/Signed_number_representation), though the [C# spec](http://www.ecma-international.org/publications/standards/Ecma-334.htm) does not explicitly require this method for representing signed integers). This knowledge is necessary to understand why treating them as unsigned makes them follow after positive numbers. – stakx - no longer contributing Aug 09 '13 at 14:27