При объявлении перечисления следует ли принудительно использовать тип byte для менее 256 объектов?

Если у вас есть перечисление в вашем приложении, и у вас есть только несколько элементов, должны ли вы сделать базовый тип наименьшим возможным типом?

    enum smaller : byte
    {
        one,
        two,
        three
    };

person ghost    schedule 15.03.2009    source источник
comment
Чтобы было ясно, я говорил о лучших практиках, а не об оптимизации, хотя этот вопрос был воспринят как вопрос оптимизации. Моя точка зрения заключалась в том, что, поскольку вы можете указать это, вы всегда должны указывать или должны решать компилятор?   -  person ghost    schedule 16.03.2009
comment
Вы можете увидеть примеры этого в структуре, например, Shutdown enum referencesource.microsoft.com/#PresentationFramework/src/   -  person StayOnTarget    schedule 11.02.2020


Ответы (7)


Нет. Не оптимизируйте преждевременно, если вы не доказали с помощью профилировщика, что это действительно проблема.

person JaredPar    schedule 15.03.2009
comment
Я думаю, что .NET в любом случае оптимизирован для того, чтобы Enums были целыми числами. - person Ray; 16.03.2009
comment
Чтобы было ясно, я говорил о лучших практиках, а не об оптимизации, хотя этот вопрос был воспринят как вопрос оптимизации. Моя точка зрения заключалась в том, что, поскольку вы можете указать это, вы всегда должны указывать или должны решать компилятор? Я думаю, оставить как есть работает для обоих. - person ghost; 16.03.2009
comment
как бы вы доказали с помощью профилировщика, что байт или целое более эффективно? - person Brian R. Bondy; 16.03.2009
comment
@ Брайан, много разных способов. Первое, что приходит на ум, это статистика памяти. Если вы заметили, что конкретный объект создается в достаточно большом количестве, чтобы его размер был заметен в профилировщике, вы можете начать искать способы уменьшить размер структуры. Это была бы одна из возможностей. - person JaredPar; 16.03.2009
comment
Я не думаю, что вы заметили бы перечисления для типичного использования, но я думаю, что это ваша точка зрения :) - person Brian R. Bondy; 16.03.2009
comment
@ Брайан точно :). Я не говорю, что эта оптимизация бесполезна. Мы делали этот тип оптимизации раньше в нашей кодовой базе (обычно битовые флаги C++). Но у нас было много данных профиля, чтобы подтвердить это, когда мы это сделали. - person JaredPar; 16.03.2009
comment
Если вы с помощью профилировщика докажете, что проблема в чем-то, это не будет преждевременной оптимизацией. - person strager; 16.03.2009
comment
Если вы хотите сбрить до 5 бит на перечисление, я бы сказал, переключитесь на другой язык/фреймворк. Я бы больше беспокоился о сильных ссылках, чем об этом - person Chris S; 16.03.2009
comment
@Chris S Откуда взялись 5 бит? int — 32 бита, byte — 8 бит. - person 0b101010; 16.03.2015
comment
@ 0b101010 у него есть 3 значения в его перечислении, поэтому он хочет использовать только 3 бита, а не 8 (поэтому экономит 5 бит) - person Chris S; 17.03.2015
comment
@ChrisS Я не интерпретировал вопрос как заданный. ОП спрашивал об изменении значения по умолчанию int на меньшее byte. Спецификация C# явно указывает, что базовый тип перечисления должен быть byte, sbyte, short, ushort, int, uint, long или ulong. Я думаю, вы можете неправильно понять, как работают перечисления. - person 0b101010; 17.03.2015
comment
Я подхожу к этому с другой точки зрения. Я пишу много сетевых и последовательных протоколов, в которых важно иметь переменные правильного типа. Я использую UInt32 UInt16 и им подобные вместо uint, ushort и т.п. для удобства и во избежание ошибок. В моем случае я обычно заставляю тип перечисления соответствовать определению протокола, чтобы я мог сериализовать его напрямую. - person Loudenvier; 11.08.2015
comment
требуется, чтобы второй параметр, переданный в Enum.IsDefined, соответствовал типу перечисления. в противном случае метод выдает исключение. так как я разбирал файл, я изменил тип перечисления на short вместо приведения параметра к int - person M.kazem Akhgary; 11.01.2017
comment
@JaredPar как насчет потребления памяти? что, если я сохраню этот тип в кеше - person omriman12; 08.12.2019

Что касается передового опыта:

Если у вас нет особой причины для того, чтобы сделать перечисление типом байта, вы должны оставить его по умолчанию.

Каждый раз, когда вы используете перечисление в операторе switch, у вас должно быть предложение «по умолчанию» для недопустимого значения перечисления. Так что не имеет значения, проверяете ли вы 256-NumRealEnumValues ​​или 2^32-NumRealEnumValues. Оба будут иметь предложение по умолчанию, которое обрабатывает все недопустимые случаи.

Одной из причин явной установки типа перечисления является то, что вы хотите, чтобы ваше перечисление соответствовало другому типу в вашей программе, и вам нужно явно выполнять приведение типов между ними.

Изменение типа на наименьший размер также не поможет вам в решении проблем с версиями. Если у вас точно не указан максимальный размер перечисления. Под проблемами управления версиями я подразумеваю, когда у вас есть скомпилированная dll с использованием перечисления, затем вы добавляете новое значение перечисления, может выполняться некоторый код, который не должен был идти в предложении «по умолчанию» оператора switch.

Об эффективности:

Нет никакой выгоды с точки зрения эффективности, чтобы сделать его байтом.

int более эффективно использовать, потому что процессор на x86 имеет 32-битные регистры. Копирование в регистр выполняется по 32 бита за раз.

Когда вы используете меньший тип, вы должны обнулить часть регистра и скопировать в остальные младшие биты регистра.

person Brian R. Bondy    schedule 16.03.2009
comment
Вы думаете только о производительности процессора. Хотя стоимость обнуления требуемых битов регистра практически незначительна, выигрыш в эффективности использования памяти может быть существенным. - person 0b101010; 16.03.2015
comment
может быть существенным, технически верно, но я сомневаюсь, что очень часто оно окажется существенным. По моему опыту, одиночные байты (не в массивах) чаще всего дополняются до границы слова, поэтому многие байты занимают столько же памяти, сколько и целое число. - person Luke; 17.03.2016
comment
как насчет того, когда я использую перечисления в структурах? Нужно ли уменьшать их до байта, чтобы уменьшить размер всей структуры? - person ccalboni; 03.04.2019
comment
Как насчет массива перечислений? Это странная идея, но теоретически массив байтовых enum-ов будет использовать в 4 раза меньше памяти, чем int-s. - person i486; 22.09.2019

Единственная причина сделать это, если вы сохраняете или передаете это значение, используя определенный протокол, который требует, чтобы поле было такого размера.

person Juliano    schedule 16.03.2009
comment
Я бы не сказал, что это единственная причина. Я часто делаю это, потому что мне нужно хранить в памяти сто миллионов или более элементов, а экономия трех байтов на запись весьма значительна. - person Jim Mischel; 16.03.2009
comment
@Jim: Если у вас так много элементов в памяти, более вероятно, что у вас есть проблема где-то еще. Вы жертвуете производительностью ради места. Вы должны либо поменять местами эти элементы из памяти, либо получить больше памяти. - person Juliano; 16.03.2009
comment
@Juliano Я не думаю, что это указывает на проблему в другом месте. В мире алгоритмической торговли в реальном времени вам часто приходится хранить в памяти миллионы элементов данных (например, транзакции, обновления книги ордеров) одновременно. Сокращение 3 байтов на элемент данных дает значительное преимущество. - person 0b101010; 16.03.2015

Если вы сопоставляете модель с перечислением с другой моделью или сериализуете ее, или ваше перечисление отражается в столбце базы данных — тогда я бы посоветовал вам указать тип явно.


Сценарий: у вас есть столбец в базе данных: status_id с типом tinyint. И у вас есть enum в вашем коде: enum Status { Well = 1, Bad = 2 }. И вы используете это перечисление в какой-то сущности. Допустим, вы используете фреймворки сущностей ядра 2.0. Если вы попытаетесь прочитать/записать этот объект из базы данных, вы получите сообщение об ошибке «Невозможно преобразовать объект», если только вы явно не укажете тип byte.

person Sergey Koval    schedule 22.02.2018
comment
Кажется, это единственная веская причина для этого. Если вы просто сопоставляете модель данных типа tinyint, то это нормально. Вы все еще, вероятно, используете байтовое значение... - person iGanja; 29.04.2019

Что бы получить? Вы сэкономите колоссальные 3 байта памяти за счет немного более медленного выполнения и менее интуитивно понятного или читаемого кода. (Читая это, я должен задаться вопросом, действительно ли у вас была причина для того, чтобы сделать его байтом, и какова могла быть эта причина. Предположительно, вы старались изо всех сил использовать нестандартный тип по какой-то причине).

Если вы планируете хранить миллионы таких вещей, то да, экономия нескольких байтов на каждой может окупиться. В противном случае нет.

По той же причине вы обычно не используете byte или short вместо int.

person jalf    schedule 15.03.2009
comment
Я использую перечисление для очистки магических чисел, которые должны быть байтами (добавление в список байтов). В данном случае это полезно. В любом другом случае это действительно была бы микрооптимизация. - person Lonefish; 21.11.2019

Вы не должны назначать перечислениям определенный целочисленный тип и позволять C# вернуться к стандартному int1 , но позволить среде .NET определить наилучший размер для перечисления. Как сказал JaredPar, если вы меняете тип данных, вы обязательно должны проверить, действительно ли это помогает.

Дело в том, что 32-битные целые числа естественны для процессоров x86, потому что их можно легко выровнять оптимальным образом.

1 По умолчанию , связанные постоянные значения членов перечисления имеют тип int

person Christian Klauser    schedule 15.03.2009
comment
.NET не определяет лучший размер перечисления. По умолчанию связанные постоянные значения членов перечисления имеют тип int; - person Trisped; 14.08.2020

В ядре .Net, если вы вызываете Enum.IsDefined, чтобы проверить, существует ли передаваемое значение в перечислении, вы должны убедиться, что типы совпадают.

ArgumentException: Базовый тип Enum и объект должны быть одного типа или объект должен быть строкой.

person Bonelol    schedule 01.12.2020