Как работает enum.toString() работает под капотом?
Я разработчик iOS и сожалею, что в Objective-C нет удивительного метода toString для перечисления, как в C#
Поэтому мне очень любопытно узнать, как метод toString работает для перечисления в C#.
Может быть, с вашими ответами я пойму, почему Objective-C не реализовал этот метод.
Спасибо
4 ответов:
Компилятор C# фактически превращает перечисления в обычные типы
classи заставляет их вести себя как перечисление комбинацией синтаксического сахара и некоторой помощью методов в .NET framework (в частности,Typeи ещеEnumклассы).На самом деле, когда вы объявляете Тип
enum, компилятор создает скрытый, специально именованный класс, который концептуально выглядит следующим образом:public sealed class EnumName : Enum { public static readonly int FirstValue = 0; public static readonly int SecondValue = 1; // etc. }Базовый класс
Enumявляется специальным базовый класс, который нельзя использовать напрямую. Он предоставляет методToString(). Это запускает серию вызовов функций, внутренних для платформы .NET framework. Код заканчивается вType.GetEnumName()и, наконец, частный методType.GetEnumData(), который использует отражение для изучения классаEnumName, просмотра его полей (значений перечисления) и получения и возврата их имен.График вызовов (в хронологическом порядке) выглядит следующим образом:
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()звонкиType.GetFields()и перебирает их, копируя свои имя и целочисленное значение (enum value) каждого поля в выходном массиве.
Внутренне
ToStringвызовет метод под названиемEnum.InternalFormat, который в свою очередь просто вызываетEnum.GetName, вот декомпилированный код (.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); }Для перечислений, помеченных атрибутом
Flags, он вызывает другой методInternalFlagsFormat, который создает CSV всех имен перечислений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"; }Для последней реализации см.Microsoft source reference .
ToString просто возвращает строку, равную имени конкретного значения enum (обратите внимание, что это может отличаться от его значения).
public enum SomeEnum { Text1 = 1, Text2 = 2, Text3 = 3, } var some = SomeEnum.Text1
some.ToString()возвращает"Text1"В случае помеченного перечисления (используя FlagsAttribute в объявлении) он вернет строку, равную всем выбранным значениям перечисления
var some = SomeEnum.Text1 & SomeEnum.Text2
"Text1 | Text2"
Если у нас есть экземпляр перечисляемого типа, мы можем сопоставить это значение одному из нескольких строковых представлений, вызвав метод ToString, унаследованный от System.Перечисление
Ниже приведен пример кода
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) } }
Comments