UnsafeAccessor是.NET 8+中专为高性能底层场景设计的不安全访问机制,需启用unsafe上下文、ref返回、extern声明,仅适用于序列化器、内存池等零开销需求,误用将导致JIT崩溃或VerificationException。

UnsafeAccessor 不是“访问私有成员的通用教程工具”,它只在 .NET 8+ 中为极少数高性能、底层场景提供绕过封装的合法通道;用错地方会直接导致 JIT 崩溃或运行时 VerificationException,且编译器不报错。
UnsafeAccessor 必须显式启用 unsafe 上下文
即使只声明一个 [UnsafeAccessor] 方法,项目也必须开启 AllowUnsafeBlocks。否则编译直接失败,错误信息是:CS0227: Unsafe code may only appear if compiling with /unsafe。
操作步骤:
- 在
.csproj文件中添加:<PropertyGroup> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> </PropertyGroup>
- 所有含
[UnsafeAccessor]的源文件顶部需加unsafe关键字(哪怕没写指针):unsafe static class Accessors { ... } - VS 中若未识别,需重启项目或清除
obj/目录重新加载
字段访问必须用 ref 返回 + extern 声明
想读写 List<T>._items 这类私有字段,不能返回值类型,必须用 ref T —— 因为 JIT 需要直接映射内存地址,返回副本会失去意义,且编译器会拒绝。
常见错误写法:
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_items")] static extern int[] GetItems(List<int> list); // ❌ 编译失败:必须是 ref
正确写法:
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_items")] static extern ref int[] GetItems(List<int> list); // ✅
使用时注意:
- 调用后得到的是
ref int[],可直接赋值或索引:GetItems(list)[0] = 42; - 不能用于
readonly字段,除非目标字段本身不是readonly(JIT 会校验字段实际修饰符) - 字段名拼错(如
"_Items")不会编译报错,而是在 JIT 编译该方法时抛出VerificationException
Method 和 Property 访问需匹配签名与 extern 修饰
访问私有方法(如 get_Value)或属性访问器,[UnsafeAccessor] 声明必须和 IL 签名完全一致,包括 extern、static、返回类型、参数类型 —— 少一个 ref 或多一个 in 都会失败。
可完全访问 Exchange 2010 EWS,管理邮件、文件夹、附件、日历事件、联系人、任务及外出设置。
例如访问 class A { private int Value { get; set; } }:
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Value")] static extern int GetValueUnsafe(A a); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_Value")] static extern void SetValueUnsafe(A a, int value);
关键点:
-
Name必须是编译期确定的字面量,不能是变量或字符串拼接 - 属性访问器在 IL 中是独立方法(
get_XXX/set_XXX),不能写成Name = "Value" - 若方法有
ref参数,声明中必须体现,否则 JIT 校验失败 - 不支持泛型方法特化(如
get_Item<T>),仅支持具体签名
它不适合单元测试或业务逻辑代码
很多人误以为 UnsafeAccessor 是反射的“更快替代品”,用来测私有方法 —— 这是危险的误用。它的设计目标明确:序列化框架、内存池管理器、高性能集合包装器等需要零开销访问内部状态的底层库。
真正该用的地方:
- 自定义
Span<T>或Memory<T>的底层适配器,需直触List<T>._items和._size - JSON 序列化器(如 System.Text.Json)跳过属性 getter,直接序列化字段布局
- 测试框架内建的高性能对象快照比对(如 PrivateProxy 生成的代理)
不该用的地方:
- 业务类中临时读一个
_cache字段做调试 - 单元测试里调用私有方法验证逻辑分支
- 跨程序集访问 internal 成员(它不解决可见性,只绕过封装检查)
最易被忽略的一点:它不提供任何运行时兼容性兜底 —— 如果目标类在后续版本中重命名字段、改变布局或转为 record,你的 [UnsafeAccessor] 会静默失效,直到 JIT 编译那一刻才崩溃,且堆栈里看不到源码行号。

















