Комментарии 20
Сюда же в копилку можно добавить Enum.HasFlag, по тем же причинам.
HasFlag
вообще расстроил. :(
При его вызове аж 2 явные команды упаковки, если мы работаем напрямую с экземпляром перечисления.
Код на C#:
enum Origin { None }
void Test(Origin origin)
{
var eq = origin.HasFlag(Origin.None);
}
IL:
.method private hidebysig instance void
Test(valuetype HasFlagTest.Program/Origin origin) cil managed
{
// Code size 19 (0x13)
.maxstack 8
IL_0000: ldarg.1
IL_0001: box HasFlagTest.Program/Origin
IL_0006: ldc.i4.0
IL_0007: box HasFlagTest.Program/Origin
IL_000c: call instance bool [mscorlib]System.Enum::HasFlag(class [mscorlib]System.Enum)
IL_0011: pop
IL_0012: ret
}
Да, но он девиртуализирован в .NET Core и не аллоцирует ;-)
Вы ассемблер смотрите, а не IL. Очевидное "неочевидно", может быть неочевидно.
Правда ваша.
Но в случае для .NET Framework, в принципе, достаточным оказалось посмотреть выделение памяти / сборку мусора.
Это да.
Просто привычка. https://sharplab.io/
Удобная штукенция.
По поводу Equals(object,object) - у нас уже есть фикс для этого в dotnet/runtime, но пока это еще не вмерженно. Там необходим escape analysis чтобы понять что бокшенный value type никуда не убегает и можно не боксить, либо эмулировать боксинг но на стеке.
А будет какое-то отличие в поведении, если перечислениям в enum будет присвоено явное значение?
enum Colors {
Red = 1,
Green = 2,
Blue = 3
}
Единственное насторожило это низкий уровень входа в шарпы) если сравнить с питоном, то шарп имеет очень высокий уровень вхождения)
Если вы собрались писать оптимальный кол на шарпе, то неожиданный боксинг/анбоксинг это одно из первых мест куда надо смотреть. Чтобы упростить эту задачу, сто лет назад изобрели плагин для решарпера/райдера: https://plugins.jetbrains.com/plugin/9223-heap-allocations-viewer. Ну а решарпер/райдер это must have
Не слышал про такой, возьму на заметку на всякий.
Мы недавно занимались оптимизациями, как раз дописал статью на эту тему. Были разного рода оптимизации, в том числе в некоторых местах приходилось экономить на каждом временном объекте.
Собственно, насколько помню, с упаковкой проблемы были в одном месте - описанном в этой статье. Может быть повезло просто, конечно. А может и нет. :)
Про маст хэш - очень холиварно. На наших солюшенах он виснет и не даёт нормально работать (ссд, нвме).
Но то, что есть плагин - хорошо.
Просто поделюсь болью: в Unity (Mono) не спасает EqualityComparer.Default. Для enum используется EnumEqualityComparer<T>, который реализует Equals как
return JitHelpers.UnsafeEnumCast<T>(x) == JitHelpers.UnsafeEnumCast<T>(y)
а UnsafeEnumCast это
return Array.UnsafeMov<T, int>(val)
который
return (R) (object) instance
...
D:
Подводные камни при работе с enum в C#