Доступ к Закрытым Членам Класса без Рефлексии в .NET 8
Закрытые члены класса в C# создаются для того, чтобы к ним нельзя было получить доступ извне. Но если нельзя, а очень хочется… то в .NET 8 появился ещё один способ получить к ним доступ без использования рефлексии.
Рассмотрим следующий класс:
class Sample.NET 8 предоставляет новый атрибут
{
// Конструкторы
private Sample() { }
private Sample(int value) { }
// Поле
private int field1 = 1;
// Статическое поле
private static int staticField = 2;
// Методы
private int Method(int value) => value;
private static int StaticMethod(int value) => value;
}
[UnsafeAccessor]. Чтобы получить доступ к закрытому члену, вы можете объявить внешний (extern) метод с атрибутом [UnsafeAccessor], чтобы объявить метод доступа для закрытого члена. Реализация метода, аннотированного этим атрибутом, будет предоставлена средой выполнения на основе информации в атрибуте и сигнатуры метода, к которому применяется атрибут. Обратите внимание, что UnsafeAccessor менее функционален, чем рефлексия. Например, вы не можете получить доступ к свойствам, а также обобщённые типы пока не полностью поддерживаются.Конструкторы
var sample1 = CallConstructor();Методы
var sample2 = CallConstructorWithArg(1);
// Возвращаемый тип метода должен быть типом класса
[UnsafeAccessor(
UnsafeAccessorKind.Constructor)]
extern static Sample CallConstructor();
[UnsafeAccessor(
UnsafeAccessorKind.Constructor)]
extern static Sample CallConstructorWithArg(int value);
var sample = CallConstructor();В статических методах так же. Несмотря на то, что экземпляр не требуется, среда выполнения должна знать тип:
Console.WriteLine(Method(sample, 1));
// Первый аргумент – экземпляр класса
[UnsafeAccessor(
UnsafeAccessorKind.Method,
Name = "Method")]
extern static int
Method(Sample @this, int value);
Console.WriteLine(StaticMethod(null, 2));Поля
[UnsafeAccessor(
UnsafeAccessorKind.StaticMethod,
Name = "StaticMethod")]
extern static int StaticMethod(Sample @this, int value);
Используем "ref", чтобы получить ссылку на поле для чтения и записи в него:
[UnsafeAccessor(UnsafeAccessorKind.Field,В readonly поля также возможна запись, как и при использовании рефлексии.
Name = "field1")]
extern static ref int
GetField(Sample @this);
var sample = CallConstructor();
_ = GetField(sample);
GetField(sample) = 42;
Аналогично со статическими полями. Как и для статических методов, необходим аргумент с типом класса:
[UnsafeAccessor(Вы можете записывать в static readonly поля, но с осторожностью. Эти поля очень похожи на константы для JIT. Поэтому запись значения в них может приводить к непредсказуемому поведению, т.к. значение может не читаться повторно в дальнейшем. Заметьте, что это невозможно при использовании рефлексии.
UnsafeAccessorKind.StaticField,
Name = "staticField")]
extern static ref int
GetStaticField(Sample @this);
_ = GetStaticField(sample);
Помните, что имя атрибута начинается с "Unsafe", потому что позволяет делать небезопасные вещи.
Источник: https://www.meziantou.net/accessing-private-members-without-reflection-in-csharp.htm