C#中UnsafeAccessor实现访问私有成员

C#中UnsafeAccessor实现访问私有成员

我们在开发时会经常遇到一个类中需要访问另一个类中私有成员的情况,但是.net是不允许直接访问的。UnsafeAccessor让这种操作成为可能。

使用反射

在.net8之前可以使用反射来实现访问私有成员

1
2
3
4
5
6
7
public class MyClass
{
private int _value = 10;
}

var a = new MyClass();
var v = typeof(MyClass).GetField("_value",BindingFlags.NonPublic|BindingFlags.Instance).GetValue(a);

使用反射来获取私有成员的方式还是比较优雅的,但是性能略差,其实还有两种性能比较高的方式分别是EmitExpression,但是这两种实现方式实现起来不够优雅,在这里不多介绍,有兴趣可以自行学习。

使用UnsafeAccessor

.net8引入了UnsafeAccessor类来实现访问私有变量,而且性能极高,和直接访问不相上下。

1
2
3
4
5
6
7
8
9
10
11
public class MyClass
{
private int _value = 10;
}

[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_value")]
static extern ref int GetValue(MyClass c);


var a = new MyClass();
var v= GetValue(a);

UnsafeAccessor存在于System.Runtime.CompilerServices命名空间中,然后必须定义一个staic extern ref,返回类型为私有变量的类型,参数就是实例类型。在方法上面我们需要添加一个UnsafeAccessor特性,这个特性有一个参数UnsafeAccessorKind,这个参数表示我们要访问的是什么类型的私有成员,比如字段、属性、方法等等,这里我们要访问的是字段,所以我们传入的是UnsafeAccessorKind.Field,然后我们还需要指定要访问的字段的名称,这里我们要访问的是_value字段,所以我们传入的是Name = "_value",这样我们就可以通过UnsafeAccessor来访问私有成员了

而且因为返回ref的引用,可以直接修改私有字段

1
2
3
var a = new MyClass();
ref var value = ref GetValue(a);
value = 20;

目前UnsafeAccessor的局限性:

  1. 不支持泛型,也许会在后续版本更新
1
2
3
//错误用法
[UnsafeAccessor(UnsafeAccessorKind.Field, Name="_myList")]
static extern ref List<T> Field<T>(MyClass<T> _this);
  1. 不支持私有类型如private class MyClass
  2. 不支持静态类

C#中UnsafeAccessor实现访问私有成员

https://bubuweiying.site/CSharp中UnsafeAccessor用法/

作者

步步为营

发布于

2024-06-25

更新于

2025-03-15

许可协议