在 dotnet runtime Github repo 上有a proposal for adding
HashSet.GetOrAdd(T)
- similar to
public static T GetOrAdd<T>(this HashSet<T> hashSet, T equalValue)
{
if (hashSet.TryGetValue(equalValue, out var actualValue))
return actualValue;
hashSet.Add(equalValue);
return equalValue;
}
但没有重复的哈希查找(性能影响)。
该问题已通过以下决议解决:
我们正在为 #15059 走 CollectionsMarshal 路线,我们 应该为 HashSet 考虑类似的方法
在 issue #15059 最后一条评论有一个 CollectionsMarshal 用于 Dictionary 的例子:
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> valueFactory)
where TKey : notnull
{
if (dictionary == null)
throw new ArgumentNullException(nameof(dictionary));
if (valueFactory == null)
throw new ArgumentNullException(nameof(valueFactory));
ref TValue? value = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out bool exists);
if (!exists)
value = valueFactory(key);
return value!;
}
我尝试使用相同的方法来实现
HashSet.GetOrAdd(T)
扩展但失败了 - 我不知道如何为 CollectionsMarshal.GetValueRefOrAddDefault()
方法获取 key值。
这两个问题都被锁定为已解决并仅限于合作者 - 所以我不能直接在那里提问。
MS的答案(只能创建执行双重查找的扩展方法):
郑重声明,使用 CollectionsMarshal for HashSet 被证明是 不可行,因为你不能对键进行引用返回 - #82840(评论)
也就是说,共识是 HashSet 的 GetOrAdd 方法是 与仅使用 HashSet.Add 相比不是特别有价值,除了 对于需要访问实际实例的罕见情况 存储在 HashSet 中 - #82875(评论)