Background and motivation
The alternate lookup for ConcurrentDictionary<TKey, TValue> is missing the GetOrAdd overloads, which makes it necessary to do a wasteful secondary lookup to try to get a value and add it if not present. We need to do this in several startup paths in CsWinRT, meaning that without a GetOrAdd we'd end up hitting the second lookup for basically every single marshalled type requiring dynamic type checks at startup:
public static Type Get(ReadOnlySpan<char> runtimeClassName)
{
var alternate = TypeNameToMappedTypes.GetAlternateLookup<ReadOnlySpan<char>>();
if (alternate.TryGetValue(runtimeClassName, out Type? type))
{
return type;
}
type = typeof(int); // Get the value from somewhere
if (alternate.TryAdd(runtimeClassName, type))
{
return type;
}
return alternate[runtimeClassName];
}
The code is also very verbose and clunky, on top of being inefficient.
API Proposal
namespace System.Collections.Concurrent;
partial class ConcurrentDictionary<TKey, TValue>
{
partial struct AlternateLookup<TAlternateKey>
{
+ public TValue GetOrAdd(TAlternateKey key, Func<TAlternateKey, TValue> valueFactory);
+ public TValue GetOrAdd<TArg>(TAlternateKey key, Func<TAlternateKey, TArg, TValue> valueFactory, TArg factoryArgument) where TArg : allows ref struct;
+ public TValue GetOrAdd(TAlternateKey key, TValue value);
}
}
API Usage
The above snippet can then become just this:
public static Type Get(ReadOnlySpan<char> runtimeClassName)
{
var alternate = TypeNameToMappedTypes.GetAlternateLookup<ReadOnlySpan<char>>();
return alternate.GetOrAdd(runtimeClassName, GetTypeFromRuntimeClassName);
}
Way simpler, and with no repeated lookups and unnecessary overhead.
Risks
None, these APIs already exist and are well established on ConcurrentDictionary<TKey, TValue> itself.
Background and motivation
The alternate lookup for
ConcurrentDictionary<TKey, TValue>is missing theGetOrAddoverloads, which makes it necessary to do a wasteful secondary lookup to try to get a value and add it if not present. We need to do this in several startup paths in CsWinRT, meaning that without aGetOrAddwe'd end up hitting the second lookup for basically every single marshalled type requiring dynamic type checks at startup:The code is also very verbose and clunky, on top of being inefficient.
API Proposal
namespace System.Collections.Concurrent; partial class ConcurrentDictionary<TKey, TValue> { partial struct AlternateLookup<TAlternateKey> { + public TValue GetOrAdd(TAlternateKey key, Func<TAlternateKey, TValue> valueFactory); + public TValue GetOrAdd<TArg>(TAlternateKey key, Func<TAlternateKey, TArg, TValue> valueFactory, TArg factoryArgument) where TArg : allows ref struct; + public TValue GetOrAdd(TAlternateKey key, TValue value); } }API Usage
The above snippet can then become just this:
Way simpler, and with no repeated lookups and unnecessary overhead.
Risks
None, these APIs already exist and are well established on
ConcurrentDictionary<TKey, TValue>itself.