从 .NET 6 开始,无需使用包装器 - 使用CollectionsMarshal.GetValueRefOrNullRef反而:
获取对 a 的引用TValue
in the Dictionary<TKey, TValue>
或参考null
如果字典中不存在。
var x = new Dictionary<string, string>{{"test", "1"}};
ref var valueRefOrNullRef = ref CollectionsMarshal.GetValueRefOrNullRef(x, "test");
if (!Unsafe.IsNullRef(ref valueRefOrNullRef))
{
valueRefOrNullRef = "2";
}
Console.WriteLine(x["test"]); // prints 2
UPD
全面实施:
public static bool TryUpdate<TKey, TValue>(
this Dictionary<TKey, TValue> source,
TKey key,
TValue value)
where TKey : notnull
{
ArgumentNullException.ThrowIfNull(source);
ref var valueRefOrNullRef = ref CollectionsMarshal.GetValueRefOrNullRef(source, key);
if (Unsafe.IsNullRef(ref valueRefOrNullRef))
{
return false;
}
valueRefOrNullRef = value;
return true;
}
var x = new Dictionary<string, decimal> { { "test", 1 } };
Console.WriteLine(x.TryUpdate("test", 2)); // True
Console.WriteLine(x.TryUpdate("test1", 2)); // False
Console.WriteLine(x["test"]); // 2
Console.WriteLine(x.ContainsKey("test2")); // False
请注意,此方法有以下限制(与包装器相比):
不应添加或删除项目Dictionary<TKey, TValue>
而ref TValue
正在使用中。
UPD2
只是为了搞笑创造了一个小基准(当然并不理想,它至少严重错过了字符串和字典大小差异)但似乎即使对于小字典和小/中字符串长度,通过键进行单次访问的方法也更快:
Method |
Mean |
Error |
StdDev |
BothUsingCollectionsMarshal |
204.92 ns |
2.008 ns |
1.677 ns |
BothUsingDoubleAccess |
355.74 ns |
5.947 ns |
6.107 ns |
OnlyPresentUsingCollectionsMarshal |
116.19 ns |
2.225 ns |
2.081 ns |
OnlyPresentUsingDoubleAccess |
271.66 ns |
5.423 ns |
5.326 ns |
OnlyMissingUsingCollectionsMarshal |
91.20 ns |
1.851 ns |
1.818 ns |
OnlyMissingUsingDoubleAccess |
94.78 ns |
1.891 ns |
2.524 ns |