【发布时间】:2019-10-15 19:32:32
【问题描述】:
我正在尝试在 C# 中实现固定大小的数组,这些数组由 hacky 类型级数字参数化。见GitHub
我想实现一个方法,它会像这样工作:
static ref T Ref(this ref TContainer container, int index)
where T: unmanaged
where TContainer: unmanaged
=> ref container[index];
现在的问题是:我知道,TContainer 内部由 N 个 T 类型的字段组成。但它实际上并没有实现索引操作(或任何接口)。
我能做的是:
CheckIndex(index);
fixed (TContainer* self = &container) {
T* data = (T*)self;
return ref data[index];
}
这与unsafe 编译,但我有两个问题:
- 是否会正确跟踪像这样检索到的托管引用的生命周期?
- 在这种情况下使用
fixed是否有任何性能成本? (例如 GC pinning、别名问题等)
此外,即使我将参数类型 ref TContainer 替换为 TContainer,或者应该相同,只需将其声明为实例成员,上面带有 fixed 和 return ref 的示例也可以编译而不是扩展方法。它甚至可以在示例测试用例中使用,但我不明白为什么会这样,因为在正常情况下,无法从结构实例方法返回 ref this.field。
【问题讨论】:
-
fixed 没有错误,它非常便宜,因为它实际上不需要固定。该变量具有 [pinned] 属性,如果 GC 恰好在此代码执行时收集,那么它会找到 [pinned] 并知道不移动对象。实际上是 ref data[] 会很痛苦。在对象内部生成一个内部指针,GC 必须遍历整个堆段才能找到对象。这个成本很难衡量,因为它只会增加“GC 时间百分比”的开销,而且如果 GC 在运行时运行,您会很不走运。
标签: c# return-by-reference c#-8.0