Net性能优化之UnsafeAccessor:极致私有成员访问性能

100 阅读2分钟

UnsafeAccessor介绍

.NET 8 引入的 UnsafeAccessor 特性是一种无需反射即可高效访问类私有成员(如字段、方法、属性等)的新机制。它通过静态外部方法结合运行时生成的底层访问逻辑,显著提升了性能并支持 AOT(提前编译)场景。

其核心在于:

  • 访问私有成员:支持直接访问其他类的私有字段、方法(包括构造方法)、属性等,即使这些成员不属于当前程序集。
  • 高性能:运行时生成的访问逻辑几乎与原生代码性能相当,远远优于传统反射方法(文章最后会有Benchmark测试对比)。
  • AOT 友好:无需依赖动态代码生成(如 Emit),适用于需要 AOT 编译的场景(如 iOS/Android 应用)

传统访问私有成员的方法

使用Reflection反射访问类中私有变量或方法:

using System.Reflection;
using ConsoleApp1;

var example = new Example();

var methodResult = typeof(Example).GetMethod("Method", BindingFlags.Instance | BindingFlags.NonPublic)
    !.Invoke(example, Array.Empty<object>());

var fieldResult = typeof(Example).GetField("Field", BindingFlags.Instance | BindingFlags.NonPublic)
    !.GetValue(example);

Console.WriteLine(methodResult);
Console.WriteLine(fieldResult);

public class Example
{
    private string Field = "test";

    private string Method()
    {
        return "Test";
    }
    
}

使用UnsafeAccessor访问私有成员

在Net8版本中用新的方式实现:

using System.Runtime.CompilerServices;

var example = new Example();

var methodResult  = Caller.GetMethod(example);

var fieldResult = Caller.GetField(example);

Console.WriteLine(methodResult);
Console.WriteLine(fieldResult);

public class Caller
{
    [UnsafeAccessor(UnsafeAccessorKind.Method,Name = "Method")]
    public static extern string GetMethod(Example example);
    [UnsafeAccessor(UnsafeAccessorKind.Field,Name = "Field")]
    public static extern ref string GetField(Example example);
}

public class Example
{
    private string Field = "test";

    private string Method()
    {
        return "Test";
    }
    
}

基准测试对比

使用Benchmark测试两种方式性能:

using System.Reflection;
using BenchmarkDotNet.Attributes;

namespace ConsoleApp1;

public class ReflectionBenchmarks
{
    private readonly Example _example = new();
    private static readonly MethodInfo CachedMethod=typeof(Example).
            GetMethod("Method", BindingFlags.Instance | BindingFlags.NonPublic)!;

    [Benchmark]
    public string GetMethod_Reflection()
    {
        return (string)_example.GetType().GetMethod("Method", BindingFlags.Instance | BindingFlags.NonPublic)
            !.Invoke(_example, Array.Empty<object>())!;
    }

    [Benchmark]
    public string GetMethod_ReflectionCached()
    {
        return (string)CachedMethod.Invoke(_example, Array.Empty<object>())!;
    }

    [Benchmark]
    public string GetMethod_Unsafe()
    {
        return Caller.GetMethod(_example);
    }
}

测试结果:

从结果中可以看出,Unsafe方法性能是完全的癫狂,甚至和调用一个空方法时间相差无几。

总的来说,UnsafeAccessor 为需要突破封装性但追求高性能的场景提供了新选择,尤其适用于框架开发和 AOT 环境。