TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
C# Heppard

20 Nov 2025, 09:58

Открыть в Telegram Поделиться Пожаловаться

UnsafeAccessor #скорость

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

В этом, не самом здоровом желании, нам, конечно, поможет reflection. Код будет тривиальный, что-то вроде typeof(Entry).GetField(...) . Этот код найдёт поле в типе и вернёт нам его объектное представление.

Особо упорные ребята могут делать подобную операцию каждый вызов метода, но это крайне не оптимально на горячих участках кода. Более умные коллеги выполнят поиск поля один раз, положат его в статическую переменную и будут получать получать значение через fieldInfo.GetValue(_entry), а задавать через fieldInfo.SetValue(_entry, value).

Те, кто читал про ExpressionTree, вполне резонно будут получать и задавать значение через заранее сформированные делегаты: для получения будет что-то вроде Expression.Lambda(fieldExpression, getterParameters).Compile(), а для записи - Expression.Lambda(Expression.Assign(fieldExpression, valueParameter), setterParameters).Compile(). Этот подход значительно быстрее (раз эдак в 100) и, на моей практике, довольно часто используется.

Однако, современный .NET 8+ может предложить ещё более быстрое решение - UnsafeAccessorAttribute. Код его использования лаконичнее и проще:
private static class Accessor {
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = FieldName)]
public static extern ref int GetFieldValue(Entry entry);
}

Как мы можем заметить, доступ осуществляется через метод с ключевым словом extern, которое чаще всего ассоциируется с использованием кода внешних библиотек на других языках программирования. В данном же случае, при аннотации extern-метода с помощью UnsafeAccessor, поиск будет происходить в сборках запущенного приложения.

Сигнатура проста. UnsafeAccessorKind указывает, какой тип члена класса мы ищем (поле, метод, конструктор). Имя говорит... про имя члена класса. Ну а первый аргумент метода - в каком типе мы ищем.

Использование этого подхода примерно в 2 раза быстрее, чем с помощью ExpressionTree. В том числе за счёт того, что мы можем получить ref на поле, что, в свою очередь, означает, что мы можем менять его по ссылке и с минимальными накладными расходами. Если у вас современный .NET и существует жгучее желание по новому взглянуть на чудеса а-ля Reflection, я бы хорошенько присмотрелся к UnsafeAccessor'у. Его скорость работы сильно впечатляет. Хотя, конечно, он имеет известные ограничения.

Прочитать больше и подробнее можно у Эндрю Лока.

P.S.: Код и результаты бенчмарка в комментариях. В этом посте много кода, а ТГ, при вставлении картинки, делает сообщение узким.

1.4k 0 26 20 45
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot