Question

I am an iOS developer and I regret that in Objective-C there is no the amazing method toString for enum like in C#

So I am very curious to know how the toString method works for enum in C#.

Maybe with your answers I will understand why Objective-C has not this method implemented.

Thanks

Was it helpful?

Solution

The C# compiler actually turns enumerations into regular class types, and makes them behave like an enumeration by a combination of syntax sugar and some help from methods in the .NET framework (particularly the Type and Enum classes).

What actually happens when you declare an enum type is that the compiler creates a hidden, specially-named class which conceptually looks like this:

public sealed class EnumName : Enum
{
    public static readonly int FirstValue = 0;
    public static readonly int SecondValue = 1;
    // etc.
}

The Enum base class is a special base class that you cannot use directly. It provides the ToString() method. This sets off a series of function calls internal to the .NET framework. The code ends up in Type.GetEnumName() and finally a private Type.GetEnumData() method which uses reflection to examine the EnumName class, look at its fields (enumeration values) and get and return their names.

The call graph (in chronological order) looks like this:

Enum.ToString()
  Enum.InternalFormat(RuntimeType, object)
    Enum.GetName(RuntimeType, object)
      Type.GetEnumName(object)
        Type.GetEnumRawConstantValues()
          Type.GetEnumData(out string[], out Array)
        Type.GetEnumNames()
          Type.GetEnumData(out string[], out Array)

GetEnumData() calls Type.GetFields() and iterates over them, copying the name and integral value (enum value) of each field into the output array.

OTHER TIPS

Internally ToString will call a method called Enum.InternalFormat, which in turn just calls Enum.GetName, here's the decompiled code (.NET v4.0)

[__DynamicallyInvokable]
public override string ToString()
{
  return Enum.InternalFormat((RuntimeType) this.GetType(), this.GetValue());
}

private static string InternalFormat(RuntimeType eT, object value)
{
  if (!eT.IsDefined(typeof (FlagsAttribute), false))
    return Enum.GetName((Type) eT, value) ?? value.ToString();
  else
    return Enum.InternalFlagsFormat(eT, value);
}

For enums marked with the Flags attribute, it calls another method called InternalFlagsFormat which builds up a CSV of all the enum names

private static string InternalFlagsFormat(RuntimeType eT, object value)
{
  ulong num1 = Enum.ToUInt64(value);
  ulong[] values;
  string[] names;
  Enum.GetCachedValuesAndNames(eT, out values, out names, true, true);
  int index = values.Length - 1;
  StringBuilder stringBuilder = new StringBuilder();
  bool flag = true;
  ulong num2 = num1;
  for (; index >= 0 && (index != 0 || (long) values[index] != 0L); --index)
  {
    if (((long) num1 & (long) values[index]) == (long) values[index])
    {
      num1 -= values[index];
      if (!flag)
        stringBuilder.Insert(0, ", ");
      stringBuilder.Insert(0, names[index]);
      flag = false;
    }
  }
  if ((long) num1 != 0L)
    return value.ToString();
  if ((long) num2 != 0L)
    return ((object) stringBuilder).ToString();
  if (values.Length > 0 && (long) values[0] == 0L)
    return names[0];
  else
    return "0";
} 

For the latest implementation, see the Microsoft source reference.

ToString simply returns the string equivelent of the Name of the specific enum value (note, this can differ from it's value).

public enum SomeEnum {
    Text1 = 1,
    Text2 = 2,
    Text3 = 3,
}

var some = SomeEnum.Text1

some.ToString() returns "Text1"

In the case of a flagged enum (using FlagsAttribute on the declaration) it would return a string equivelent of all selected enum values

var some = SomeEnum.Text1 & SomeEnum.Text2

"Text1 | Text2"

If we have an instance of an enumerated type we can map that value to one of several string representations by calling the ToString method inherited from System.Enum

Below is the sample code

class Program
{
    enum Days
    {
        Sun,
        Mon,
        Tue,
        Wed,
        Thu,
        Fri,
        Sat
    };

    static void Main(string[] args)
    {

        Days obj = Days.Mon;

        Console.WriteLine(obj.ToString("G"));  // output - Mon (Normal)
        Console.WriteLine(obj.ToString("D"));  // output - 1 (Decimal)
        Console.WriteLine(obj.ToString("X"));  // output - 00000001 (Hexadecimal)    
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top