如何为ref struct实现传统TryGet函数以避免重复查找?
如何为ref struct编写传统的TryGet函数?
我目前有一组配套函数:
bool HasX(int key) { ... } ref S GetX(int key) { ... } // S 是 struct
它们能正常工作,但如果要先检查存在性再调用获取函数,就得两次计算数组偏移并检查值。这正是Dictionary<TK, TV>.TryGetValue(TK key, out TV value)这类函数存在的意义——只需要一次查找即可完成存在性校验和值获取。
我尝试过将二者合并为一个函数的几种方案,但都存在问题:
// 问题:ref S的语义不符合需求,无法将其设置为引用结构句柄 bool TryGetX(int key, ref S value) // 问题:out S会对struct进行值拷贝,失去了ref语义的优势 bool TryGetX(int key, out S value) // 重复方案,同上问题 bool TryGetX(int key, ref S value) // 问题:返回的是结构体拷贝而非引用,不符合需求 S? TryGetX(int key) // 问题:等价于ref Nullable<S>,而非Nullable<ref S>,不适用 ref S? TryGetX(int key) // 可行但不符合惯用写法:无法像`if(dict.TryGetValue(key, out var value))`那样简洁地作为条件使用 ref S TryGetX(int key, out bool found) // 目前最简洁但仍不符合惯用写法:失败时返回Unsafe.NullRef<S>,需要额外判空 ref S TryGetX(int key)
可行解决方案
针对ref struct的场景,有两种兼顾性能和惯用性的实现方式:
方案1:调整返回顺序,配合模式匹配优化可读性
虽然与标准TryGetValue的参数顺序相反,但可以通过模式匹配让代码接近惯用风格:
ref S TryGetX(int key, out bool exists) { // 执行一次查找逻辑:计算偏移、校验存在性 if (/* 找到对应项 */) { exists = true; return ref 目标结构体引用; } exists = false; return ref Unsafe.NullRef<S>(); }
使用示例:
if (TryGetX(key, out var exists) is var valueRef && exists) { // 直接操作valueRef,无结构体拷贝 valueRef.SomeProperty = newValue; }
方案2:自定义可空引用结果结构体
如果想要更贴近标准TryGetValue的语法,可以定义一个包含引用和存在标记的包装结构体:
readonly struct RefResult<T> where T : struct { public readonly ref T Value; public readonly bool Exists; public RefResult(ref T value, bool exists) { Value = ref value; Exists = exists; } // 隐式转换为bool,支持直接作为条件判断 public static implicit operator bool(RefResult<T> result) => result.Exists; }
实现对应的TryGet函数:
RefResult<S> TryGetX(int key) { // 一次查找逻辑 if (/* 找到对应项 */) { return new RefResult<S>(ref 目标结构体引用, true); } return new RefResult<S>(ref Unsafe.NullRef<S>(), false); }
使用示例(和标准写法高度一致):
if (TryGetX(key) is var result && result) { // 操作result.Value,无拷贝 result.Value.SomeProperty = newValue; } // 或者简化写法 var result = TryGetX(key); if (result) { // 使用result.Value }
关键注意点
- 避免使用
out S的方案,因为会产生struct拷贝,完全失去ref语义的性能优势 - 返回
Unsafe.NullRef<S>的方案必须严格检查空引用,否则会导致内存访问错误 - 自定义
RefResult<T>时建议设为readonly struct,避免不必要的结构体拷贝
内容的提问来源于stack exchange,提问作者Blindy
相关产品推荐
相关产品推荐

