enum Vehicles
{
car,
plane,
ship,
helicopter,
truck = plane
}
static void Main()
{
Console.WriteLine((Vehicles)1);//truck
Console.WriteLine((Vehicles)2);//ship
Console.WriteLine((Vehicles)100);//100
Console.WriteLine((int)Vehicles.helicopter);// 3
Console.ReadKey();
}
Я пытаюсь понять, почему, если мы явно приводим интовую переменную(или в нашем случае литерал) выводиться название переменной, которая хранит это значение, а в случае вывода литерала, которого нет в данном перечислении, выводиться сам литерал? И наоборот - если я привожу поле enum'a(если можно сказать "поле") к int, то выводиться его значение? То есть, при привидении int к Vehicles происходит поиск полей, которые хранят в себе значение этого int'a? Тогда почему в первом выводе truck, а не plane?
Все типы в CLR наследуют от System.Object
в котором определен виртуальный метод строкового представления текущего объекта – ToString
. Любой тип может переопределить этот метод, тем самым изменив представление по-умолчанию, которое определено в System.Object
– вывод полного имени типа.
Например, тип Int32
(int) переопределяет этот метод для представления хранимого значения в виде форматированного, в зависимости от региональных настроек и формата, числа.
Каждый раз, когда вы определяете перечисление, вы создаете наследника класса System.Enum
в котором, как вы уже догадались, тоже предопределен метод ToString
для представления текущего значения перечисления в виде строки. Для вашего перечисления (Vehicles), будет сгенерирован такой IL
.class private auto ansi sealed Vehicles
extends [mscorlib]System.Enum
{
.field public specialname rtspecialname int32 value__
.field public static literal valuetype Vehicles car = int32(0x00000000)
.field public static literal valuetype Vehicles plane = int32(0x00000001)
...
.field public static literal valuetype Vehicles truck = int32(0x00000001)
} // end of class Vehicles
Что соответствует примерно вот такому коду (переводчик из IL я так-себе, поэтому лучше перепроверить :)
sealed class Vehicles : System.Enum
{
public const Vehicles car = 0;
public const Vehicles plane = 1;
...
public const Vehicles truck = 1;
}
Теперь о том, как метод ToString
который используется методом Console.WriteLine
находит имя поля. В .NET есть специальный механизм, называемый рефлексия, при помощи которого можно получать информацию о произвольных типах (например, имена полей и их значений) при помощи этого механизма Enum просматривает список полей, и если есть совпадения по значению – то возвращает это имя. На практике за это отвечает этот код, который вызывается из метода Enum.ToString
private static String InternalFormat(RuntimeType eT, Object value)
{
if (!eT.IsDefined(typeof(System.FlagsAttribute), false))
{
String retval = GetName(eT, value);
if (retval == null)
return value.ToString();
else
return retval;
...
}
Из него хорошо видно, что если у перечисление нет атрибута Flags
то метод должен просто вернуть имя поля или, в случае несовпадения, вернуть значение.
Тогда почему в первом выводе truck, а не plane
Как я говорил выше, что имена всех полей и значений выбираются при помощи рефлексии. Затем код сортирует значения полей и при помощи двоичного поиска ищет совпадение. Таким образом, поиск просто вернет первое совпадение. За это отвечает этот код из System.Enum
Array values = GetEnumRawConstantValues();
int index = BinarySearch(values, value);
if (index >= 0)
{
string[] names = GetEnumNames();
return names[index];
}
Можно попробовать манипулировать этим поиском, поместив одинаковые значения на границу отрезков:
enum Vehicles
{
car = 0,
plane = 1,
cat = 2,
ship = 2,
helicopter = 3,
truck = 4
}
...
string name = ((Vehicles) 2).ToString();
Console.WriteLine(name); // cat
Но всё таки лучше присваивать разные значения полям перечисления :)
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Привет! Есть тестовая процедурка, написанная на C# CLR SQL, которая потом работает как обычная хранимкаПроцедура пытается создать файл в сетевой...
Есть класс в котором одно из свойств это объект из библиотеки dllСуть в том, что при вызове метода JsonConvert
Здравствуйте, есть капча при обновлении страницы появляеться новая