如何访问私人列表成员
本文关键字:列表 成员 何访问 访问 | 更新日期: 2023-09-27 18:36:04
一般来说,在C#中,使用List比T[更方便。但是,有时探查器显示,与本机实现的批量操作(如 Array.Copy 和 Buffer.BlockCopy)相比,List 的性能损失很大。此外,无法获取指向 List<> 元素的指针。
这使得在 Unity 中使用动态网格体有些痛苦。如果我们可以访问 T[] List._items,其中一些问题可以得到缓解。这是否可以在没有大量开销的情况下完成?(CPU 或垃圾)
如果您知道 List 的布局,则可以使用肮脏的技巧来强制转换托管对象引用。除非您愿意在运行的每个目标平台上进行测试,并在每次 Unity 升级时重新测试,否则不要使用它。
最危险的是,它破坏了有关对象的运行时和编译类型的不变量。编译器将为 TTo 类型的对象生成代码,但该对象的 RTTI 字段仍将显示 TFrom 类型的对象。
[StructLayout(LayoutKind.Explicit)]
public struct ConvertHelper<TFrom, TTo>
where TFrom : class
where TTo : class {
[FieldOffset( 0)] public long before;
[FieldOffset( 8)] public TFrom input;
[FieldOffset(16)] public TTo output;
static public TTo Convert(TFrom thing) {
var helper = new ConvertHelper<TFrom, TTo> { input = thing };
unsafe {
long* dangerous = &helper.before;
dangerous[2] = dangerous[1]; // ie, output = input
}
var ret = helper.output;
helper.input = null;
helper.output = null;
return ret;
}
}
class PublicList<T> {
public T[] _items;
}
public static T[] GetBackingArray<T>(this List<T> list) {
return ConvertHelper<List<T>, PublicList<T>>.Convert(list)._items;
}
使用反射总是可能的。这会为调用 GetValue() 生成几百字节的垃圾。它也不是很快;在 40 个列表的顺序上
// Helper class for fetching and caching FieldInfo values
class FieldLookup {
string sm_name;
Dictionary<Type, FieldInfo> sm_cache;
public FieldLookup(string name) {
sm_name = name;
sm_cache = new Dictionary<Type, FieldInfo>();
}
public FieldInfo Get(Type t) {
try {
return sm_cache[t];
} catch (KeyNotFoundException) {
var field = sm_cache[t] = t.GetField(
sm_name,
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.GetField |
System.Reflection.BindingFlags.Instance);
return field;
}
}
}
static FieldLookup sm_items = new FieldLookup("_items");
public static T[] GetBackingArray<T>(this List<T> list) {
return (T[])sm_items.Get(typeof(List<T>)).GetValue(list);
}