C
C# Heppard
@csharp_gepard1.7K подп.
2.2Kпросмотров
20 ноября 2025 г.
Score: 2.4K
UnsafeAccessor #скорость Иногда возникает странное желание изменять приватные поля в классах, код которых нам не доступен. Например, внутренний массив коллекции или настройку, которая почему-то и, по нашей логике, возмутительно не выставлена наружу. В этом, не самом здоровом желании, нам, конечно, поможет reflection. Код будет тривиальный, что-то вроде typeof(Entry).GetField(...) . Этот код найдёт поле в типе и вернёт нам его объектное представление. Особо упорные ребята могут делать подобную операцию каждый вызов метода, но это крайне не оптимально на горячих участках кода. Более умные коллеги выполнят поиск поля один раз, положат его в статическую переменную и будут получать значение через fieldInfo.GetValue(_entry), а задавать через fieldInfo.SetValue(_entry, value). Те, кто читал про ExpressionTree, вполне резонно будут получать и задавать значение через заранее сформированные делегаты: для получения будет что-то вроде Expression.Lambda<Func<Entry, int>>(fieldExpression, getterParameters).Compile(), а для записи - Expression.Lambda<Action<Entry, int>>(Expression.Assign(fieldExpression, valueParameter), setterParameters).Compile(). Этот подход значительно быстрее (раз эдак в 20) и, на моей практике, довольно часто используется. Однако, современный .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.: Код и результаты бенчмарка в комментариях. В этом посте много кода, а ТГ, при вставлении картинки, делает сообщение узким.
2.2K
просмотров
2746
символов
Нет
эмодзи
Нет
медиа

Другие посты @csharp_gepard

Все посты канала →
UnsafeAccessor #скорость Иногда возникает странное желание и — @csharp_gepard | PostSniper