Комментарии 12
на то он и unsafe, чтобы работать без каких-либо проверок в рантайме. зато вы теперь знаете, во сколько обходятся все эти “безопасные” фишки в языке.
Какие фишки? Чем отличается от безопасного доступа к публичному полю?
может там под капотом геттер втихаря вызывается, а они виртуальные, и надо вначале найти правильный, это запрос к классу, где у него геттер поля, потом вызов, всё это обернуто в код, ловящий исключения, без дизасма вызова не сказать. А тут хоп и “получить память по смещению от базового указателя”, одна инструкция, кроме того объект, если мелкий, целиком в кэш прочитан, код даже в память не ходит лишний раз.
Уходили от плюсов(и прочего "не безопасного"), костылями приделывают обратно. А как же парадигма ООП? Как же "если не должно быть видно, то прячем поглубже из публичности"?
Цель понятна ибо "надо", но путь по которому движется - стрёмен.
Способ из.NET 8 выглядит так. Метод объявлен как extern static, тела у него нет — его подставляет рантайм:
Точно в рантайме? Не смотрел реализацию, но выглядит как-то не оптимально в рантайме тратить время на генерацию кода.
Всякое бывает. Мне приходилось подменять статическую локальную функцию в библиотеке парсинга екселя, чтобы улучшить этот самый парсинг.
В плюсах по умолчанию всё опасно, а безопасность требует плясок с бубном.
В шарпе - наоборот. Так и было задумано, чтобы грязные хаки выглядели как грязные хаки и привлекали особое внимание.
Если оно по скорости такое же, как прямой доступ к полю, и работает в компайл тайме, то почему отсутствие поля с таким названием выбрасывает исключение, а не падает при компиляции? И какой IL оно подставляет, если передать несуществующее поле? Какое смещение? После конца класса, что ли?
Я так понял в момент первого вызова вычисляется смещение и jit либо генерит доступ к полю, либо генерит метод, бросающий исключение.
Поиск по имени проходит разово когда идет первая подготовка метода к выполнению. Не при компиляции.
Рантайм ищет поле по имени и не найдя бросает MissingFieldException — unsafeaccessors.cpp, строка 1146. Если найдет то сгенерит IL с обычным ldfld по смещению данного поля. Вариант вида «после конца класса» не существует прост не будет никакой генерации.
Компилятор проверить не может: имя задано строкой в атрибуте, а поле приватное и в какой сборке может быть сразу неизсетно.
А что за задача, где доли наносекунд играют роль? Это метод нужно миллиард раз дернуть и то даде секунды не будет.
Всевозможные симуляции, например.
Специально сейчас глянул один из лёгоньких своих прогонов - более 100 миллиардов индивидуальных значений, каждое пропускается через достаточно сложный вычислительный граф, несколько раз агрегируются по не самым простым наборам правил и опять пропускаются через следующий вычислительный граф.
Каждая оптимизация, очевидно, имеет накопительный эффект, и наоборот - каждая наивная "абы как"/"чистый код" имплементация тоже имеет накопительный эффект, но с противоположным знаком.
Лично наблюдал/участвовал в переписывании симуляционных движков, где время прогона снижалось сначала с суток-полутора-двух до двух-трёх часов, а потом и до часа/десятков минут.
...да даже UI - там где нужен действительно сложный/многоуровневый пересчёт подсказок/индикаторов/итого при редактировании полей и без заметного глазу лага.

А чё, так можно было? Приватное поле за 0,25 наносекунды