BiDictionary<TKey, TValue> Class
Definition
Represents a bidirectional one-to-one dictionary in which every key maps to exactly one value and every value maps back to exactly one key, providing O(1) lookup in both directions.
public sealed class BiDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable where TKey : notnull where TValue : notnull
Type Parameters
TKeySpecifies the type of keys in the dictionary.
TValueSpecifies the type of values in the dictionary.
- Inheritance
-
BiDictionary<TKey, TValue>
- Implements
-
IDictionary<TKey, TValue>ICollection<KeyValuePair<TKey, TValue>>IReadOnlyDictionary<TKey, TValue>IReadOnlyCollection<KeyValuePair<TKey, TValue>>IEnumerable<KeyValuePair<TKey, TValue>>
- Inherited Members
- Extension Methods
Remarks
BiDictionary<TKey, TValue> is the .NET analogue of Guava's BiMap, Python's bidict, and
Apache Commons' BidiMap: a hash-based map that maintains a second, inverse index from values back to keys so
that TryGetKey(TValue, out TKey), ContainsValue(TValue), and
RemoveValue(TValue) are O(1) operations rather than linear scans. The two indexes are kept atomically
consistent by every mutation.
Because the mapping is one-to-one in both directions, adding a pair whose value is already bound to a different key is a conflict. The BiDictionaryDuplicateValuePolicy chosen at construction resolves it: Throw (the default) rejects the operation, while Replace evicts the previous binding - the key that held the value is removed - so the new pair wins. Duplicate keys follow the standard Dictionary<TKey, TValue> contract: Add(TKey, TValue) throws and the indexer setter re-binds.
The Inverse property exposes the reversed mapping as a live BiDictionary<TKey, TValue> view sharing the same storage: mutations through either view are immediately visible through the other,
and Inverse.Inverse returns the original instance. Through the inverse view keys and values swap roles, so
the duplicate-value policy there governs conflicts on what the original considers its keys; in both directions the
invariant is simply that the mapping stays one-to-one.
Both type parameters are constrained by notnull - values act as lookup keys in the inverse index, so null values cannot be indexed and are rejected at run time just as null keys are. Custom equality is supported independently on each side via KeyComparer and ValueComparer.
Enumeration follows the forward index's unspecified, insertion-biased order (the same non-contractual order as Dictionary<TKey, TValue>); do not rely on it. Enumerator invalidation also matches the BCL dictionary: adding an entry - through either view - invalidates active enumerators, which then throw InvalidOperationException; do not mutate the dictionary while enumerating it.
BiDictionary<TKey, TValue> is not thread-safe. Concurrent reads and writes, including through the Inverse view, require external synchronization.
var codes = new BiDictionary<string, int>();
codes.Add("AU", 36);
codes.Add("NZ", 554);
int numeric = codes["AU"]; // 36 - forward lookup
codes.TryGetKey(554, out string? alpha); // "NZ" - O(1) inverse lookup
// The inverse view shares storage with the original.
BiDictionary<int, string> byNumber = codes.Inverse;
byNumber.Add(76, "BR");
bool present = codes.ContainsKey("BR"); // true - visible through the original
Constructors
BiDictionary()
Initializes a new instance of the BiDictionary<TKey, TValue> class that is empty, rejects duplicate values, and uses the default comparers.
public BiDictionary()
BiDictionary(BiDictionaryDuplicateValuePolicy)
Initializes a new instance of the BiDictionary<TKey, TValue> class that is empty, uses the specified duplicate-value policy, and uses the default comparers.
public BiDictionary(BiDictionaryDuplicateValuePolicy duplicateValuePolicy)
Parameters
duplicateValuePolicyBiDictionaryDuplicateValuePolicyThe policy applied when an add or assignment operation supplies a value already bound to a different key.
Exceptions
- ArgumentOutOfRangeException
duplicateValuePolicyis not a defined BiDictionaryDuplicateValuePolicy value.
BiDictionary(BiDictionaryDuplicateValuePolicy, IEqualityComparer<TKey>?, IEqualityComparer<TValue>?)
Initializes a new instance of the BiDictionary<TKey, TValue> class that is empty, uses the specified duplicate-value policy, and uses the specified key and value comparers.
public BiDictionary(BiDictionaryDuplicateValuePolicy duplicateValuePolicy, IEqualityComparer<TKey>? keyComparer, IEqualityComparer<TValue>? valueComparer)
Parameters
duplicateValuePolicyBiDictionaryDuplicateValuePolicyThe policy applied when an add or assignment operation supplies a value already bound to a different key.
keyComparerIEqualityComparer<TKey>The equality comparer to use for keys, or null to use the default comparer.
valueComparerIEqualityComparer<TValue>The equality comparer to use for values, or null to use the default comparer.
Exceptions
- ArgumentOutOfRangeException
duplicateValuePolicyis not a defined BiDictionaryDuplicateValuePolicy value.
BiDictionary(BiDictionaryDuplicateValuePolicy, int)
Initializes a new instance of the BiDictionary<TKey, TValue> class that is empty, uses the specified duplicate-value policy, has the specified initial capacity, and uses the default comparers.
public BiDictionary(BiDictionaryDuplicateValuePolicy duplicateValuePolicy, int capacity)
Parameters
duplicateValuePolicyBiDictionaryDuplicateValuePolicyThe policy applied when an add or assignment operation supplies a value already bound to a different key.
capacityintThe initial number of entries the internal hash tables can hold without resizing.
Exceptions
- ArgumentOutOfRangeException
duplicateValuePolicyis not a defined BiDictionaryDuplicateValuePolicy value, orcapacityis less than zero.
BiDictionary(BiDictionaryDuplicateValuePolicy, int, IEqualityComparer<TKey>?, IEqualityComparer<TValue>?)
Initializes a new instance of the BiDictionary<TKey, TValue> class that is empty and has the specified duplicate-value policy, initial capacity, and key and value comparers.
public BiDictionary(BiDictionaryDuplicateValuePolicy duplicateValuePolicy, int capacity, IEqualityComparer<TKey>? keyComparer, IEqualityComparer<TValue>? valueComparer)
Parameters
duplicateValuePolicyBiDictionaryDuplicateValuePolicyThe policy applied when an add or assignment operation supplies a value already bound to a different key.
capacityintThe initial number of entries the internal hash tables can hold without resizing.
keyComparerIEqualityComparer<TKey>The equality comparer to use for keys, or null to use the default comparer.
valueComparerIEqualityComparer<TValue>The equality comparer to use for values, or null to use the default comparer.
Exceptions
- ArgumentOutOfRangeException
duplicateValuePolicyis not a defined BiDictionaryDuplicateValuePolicy value, orcapacityis less than zero.
BiDictionary(IEqualityComparer<TKey>?, IEqualityComparer<TValue>?)
Initializes a new instance of the BiDictionary<TKey, TValue> class that is empty, rejects duplicate values, and uses the specified key and value comparers.
public BiDictionary(IEqualityComparer<TKey>? keyComparer, IEqualityComparer<TValue>? valueComparer)
Parameters
keyComparerIEqualityComparer<TKey>The equality comparer to use for keys, or null to use the default comparer.
valueComparerIEqualityComparer<TValue>The equality comparer to use for values, or null to use the default comparer.
BiDictionary(int)
Initializes a new instance of the BiDictionary<TKey, TValue> class that is empty, rejects duplicate values, has the specified initial capacity, and uses the default comparers.
public BiDictionary(int capacity)
Parameters
capacityintThe initial number of entries the internal hash tables can hold without resizing.
Exceptions
- ArgumentOutOfRangeException
capacityis less than zero.
BiDictionary(int, IEqualityComparer<TKey>?, IEqualityComparer<TValue>?)
Initializes a new instance of the BiDictionary<TKey, TValue> class that is empty, rejects duplicate values, and has the specified initial capacity and key and value comparers.
public BiDictionary(int capacity, IEqualityComparer<TKey>? keyComparer, IEqualityComparer<TValue>? valueComparer)
Parameters
capacityintThe initial number of entries the internal hash tables can hold without resizing.
keyComparerIEqualityComparer<TKey>The equality comparer to use for keys, or null to use the default comparer.
valueComparerIEqualityComparer<TValue>The equality comparer to use for values, or null to use the default comparer.
Exceptions
- ArgumentOutOfRangeException
capacityis less than zero.
Properties
Count
Gets the number of elements contained in the ICollection<T>.
public int Count { get; }
Property Value
- int
The number of elements contained in the ICollection<T>.
DuplicateValuePolicy
Gets the policy applied when an add or assignment operation supplies a value that is already bound to a different key.
public BiDictionaryDuplicateValuePolicy DuplicateValuePolicy { get; }
Property Value
- BiDictionaryDuplicateValuePolicy
The duplicate-value policy fixed at construction and shared with the Inverse view.
Inverse
Gets the live inverse view of this dictionary, mapping each value back to its key.
public BiDictionary<TValue, TKey> Inverse { get; }
Property Value
- BiDictionary<TValue, TKey>
A BiDictionary<TKey, TValue> sharing this instance's storage.
Remarks
The view shares the same two indexes as this instance: mutations through either view are immediately visible
through the other, and Inverse.Inverse returns this instance (reference equality). The view is allocated
on first access and cached, so repeated reads return the same instance.
Keys and values swap roles through the view - its KeyComparer is this instance's ValueComparer and vice versa - and the shared DuplicateValuePolicy governs conflicts on the value side of whichever view is being mutated.
IsReadOnly
Gets a value indicating whether the ICollection<T> is read-only.
public bool IsReadOnly { get; }
Property Value
- bool
true if the ICollection<T> is read-only; otherwise, false.
this[TKey]
Gets or sets the element with the specified key.
public TValue this[TKey key] { get; set; }
Parameters
keyTKeyThe key of the element to get or set.
Property Value
- TValue
The element with the specified key.
Remarks
Assigning a new key adds the pair; assigning an existing key re-binds it - the key's previous value is unbound from the inverse index so it no longer resolves through TryGetKey(TValue, out TKey) or ContainsValue(TValue).
When the assigned value is already bound to a different key, the conflict is resolved by DuplicateValuePolicy: Throw rejects the assignment with ArgumentException, while Replace evicts the previous binding. Re-assigning a key its own current value is never a conflict.
Exceptions
- ArgumentNullException
keyis null.- KeyNotFoundException
The property is retrieved and
keyis not found.- NotSupportedException
The property is set and the IDictionary<TKey, TValue> is read-only.
KeyComparer
Gets the IEqualityComparer<T> used to determine key equality.
public IEqualityComparer<TKey> KeyComparer { get; }
Property Value
- IEqualityComparer<TKey>
The comparer used for key identity in the forward index.
Keys
Gets an ICollection<T> containing the keys of the IDictionary<TKey, TValue>.
public ICollection<TKey> Keys { get; }
Property Value
- ICollection<TKey>
An ICollection<T> containing the keys of the object that implements IDictionary<TKey, TValue>.
Remarks
Returns the forward index's live key collection. The collection is read-only through this surface and its enumeration order matches the dictionary's (unspecified) enumeration order.
ValueComparer
Gets the IEqualityComparer<T> used to determine value equality.
public IEqualityComparer<TValue> ValueComparer { get; }
Property Value
- IEqualityComparer<TValue>
The comparer used for value identity in the inverse index.
Values
Gets an ICollection<T> containing the values in the IDictionary<TKey, TValue>.
public ICollection<TValue> Values { get; }
Property Value
- ICollection<TValue>
An ICollection<T> containing the values in the object that implements IDictionary<TKey, TValue>.
Remarks
Returns the forward index's live value collection. Because the mapping is one-to-one, the values are distinct under ValueComparer. The collection is read-only through this surface and its enumeration order matches the dictionary's (unspecified) enumeration order.
Methods
Add(KeyValuePair<TKey, TValue>)
Adds the specified key/value pair to the dictionary.
public void Add(KeyValuePair<TKey, TValue> item)
Parameters
itemKeyValuePair<TKey, TValue>The key/value pair to add to the dictionary.
Exceptions
- ArgumentNullException
item.Keyoritem.Valueis null.- ArgumentException
An element with the same key already exists in the dictionary, or the pair's value is already bound to a different key and DuplicateValuePolicy is Throw.
Add(TKey, TValue)
Adds the specified key and value to the dictionary.
public void Add(TKey key, TValue value)
Parameters
keyTKeyThe key of the element to add. Must not be null.
valueTValueThe value to bind to
key. Must not be null.
Remarks
Duplicate keys follow the strict Add(TKey, TValue) contract and always throw. A duplicate value is resolved by DuplicateValuePolicy: under Replace the previous binding holding the value is evicted - its key is removed - before the new pair is added.
Exceptions
- ArgumentNullException
keyorvalueis null.- ArgumentException
An element with the same key already exists in the dictionary, or
valueis already bound to a different key and DuplicateValuePolicy is Throw.
Clear()
Removes all entries from the dictionary.
public void Clear()
Remarks
Clears both the forward and inverse indexes, so the Inverse view is emptied as well.
Contains(KeyValuePair<TKey, TValue>)
Determines whether the ICollection<T> contains a specific value.
public bool Contains(KeyValuePair<TKey, TValue> item)
Parameters
itemKeyValuePair<TKey, TValue>The object to locate in the ICollection<T>.
Returns
- bool
true if
itemis found in the ICollection<T>; otherwise, false.
Remarks
Value equality is determined by ValueComparer, matching the comparer used by the inverse index.
ContainsKey(TKey)
Determines whether the IDictionary<TKey, TValue> contains an element with the specified key.
public bool ContainsKey(TKey key)
Parameters
keyTKeyThe key to locate in the IDictionary<TKey, TValue>.
Returns
- bool
true if the IDictionary<TKey, TValue> contains an element with the key; otherwise, false.
Exceptions
- ArgumentNullException
keyis null.
ContainsValue(TValue)
Determines whether the dictionary contains a specific value.
public bool ContainsValue(TValue value)
Parameters
valueTValueThe value to locate. Must not be null.
Returns
Remarks
This is an O(1) operation backed by the inverse index, unlike the O(n) scan of ContainsValue(TValue). Value equality is determined by ValueComparer.
Exceptions
- ArgumentNullException
valueis null.
CopyTo(KeyValuePair<TKey, TValue>[], int)
Copies the elements of the ICollection<T> to an Array, starting at a particular Array index.
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
Parameters
arrayKeyValuePair<TKey, TValue>[]The one-dimensional Array that is the destination of the elements copied from ICollection<T>. The Array must have zero-based indexing.
arrayIndexintThe zero-based index in
arrayat which copying begins.
Exceptions
- ArgumentNullException
arrayis null.- ArgumentOutOfRangeException
arrayIndexis less than 0.- ArgumentException
The number of elements in the source ICollection<T> is greater than the available space from
arrayIndexto the end of the destinationarray.
GetEnumerator()
Returns an enumerator that iterates through the collection.
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
Returns
- IEnumerator<KeyValuePair<TKey, TValue>>
An enumerator that can be used to iterate through the collection.
Remarks
Enumeration follows the forward index's unspecified, insertion-biased order. As with Dictionary<TKey, TValue>, adding an entry - through either view - invalidates the enumerator, which then throws InvalidOperationException; do not mutate the dictionary while enumerating it.
Remove(KeyValuePair<TKey, TValue>)
Removes the first occurrence of a specific object from the ICollection<T>.
public bool Remove(KeyValuePair<TKey, TValue> item)
Parameters
itemKeyValuePair<TKey, TValue>The object to remove from the ICollection<T>.
Returns
- bool
true if
itemwas successfully removed from the ICollection<T>; otherwise, false. This method also returns false ifitemis not found in the original ICollection<T>.
Exceptions
- NotSupportedException
The ICollection<T> is read-only.
Remove(TKey)
Removes the element with the specified key from the IDictionary<TKey, TValue>.
public bool Remove(TKey key)
Parameters
keyTKeyThe key of the element to remove.
Returns
- bool
true if the element is successfully removed; otherwise, false. This method also returns false if
keywas not found in the original IDictionary<TKey, TValue>.
Remarks
Removing a key also unbinds its value from the inverse index, so the value no longer resolves through TryGetKey(TValue, out TKey) or ContainsValue(TValue).
Exceptions
- ArgumentNullException
keyis null.- NotSupportedException
The IDictionary<TKey, TValue> is read-only.
RemoveValue(TValue)
Removes the key/value pair whose value equals the specified value.
public bool RemoveValue(TValue value)
Parameters
valueTValueThe value of the pair to remove. Must not be null.
Returns
Remarks
This is the value-side counterpart of Remove(TKey): it locates the owning key through the inverse index in O(1) and removes the pair from both indexes atomically.
Exceptions
- ArgumentNullException
valueis null.
TryAdd(TKey, TValue)
Attempts to add the specified key and value to the dictionary without throwing on a conflict.
public bool TryAdd(TKey key, TValue value)
Parameters
keyTKeyThe key of the element to add. Must not be null.
valueTValueThe value to bind to
key. Must not be null.
Returns
- bool
true if the pair was added; false if the key already exists, or if the value is already bound to a different key and DuplicateValuePolicy is Throw.
Remarks
This is the non-throwing counterpart of Add(TKey, TValue): both conflicts that Add(TKey, TValue) reports by throwing are reported here by returning false with the dictionary unchanged. Under Replace a value conflict instead evicts the previous binding and the method returns true.
Exceptions
- ArgumentNullException
keyorvalueis null.
TryGetKey(TValue, out TKey)
Attempts to retrieve the key bound to the specified value.
public bool TryGetKey(TValue value, out TKey key)
Parameters
valueTValueThe value whose key to retrieve. Must not be null.
keyTKeyWhen this method returns, contains the key bound to the specified value, if the value is found; otherwise, the default value for the type of the key parameter.
Returns
Remarks
This is the value-side counterpart of TryGetValue(TKey, out TValue) and is an O(1) operation backed by the inverse index. Value equality is determined by ValueComparer.
Exceptions
- ArgumentNullException
valueis null.
TryGetValue(TKey, out TValue)
Attempts to retrieve the value bound to the specified key.
public bool TryGetValue(TKey key, out TValue value)
Parameters
keyTKeyThe key of the value to retrieve. Must not be null.
valueTValueWhen this method returns, contains the value bound to the specified key, if the key is found; otherwise, the default value for the type of the value parameter.
Returns
Exceptions
- ArgumentNullException
keyis null.
Explicit Interface Implementations
IReadOnlyDictionary<TKey, TValue>.Keys
Gets an enumerable collection that contains the keys in the read-only dictionary.
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys { get; }
Returns
- IEnumerable<TKey>
An enumerable collection that contains the keys in the read-only dictionary.
IReadOnlyDictionary<TKey, TValue>.Values
Gets an enumerable collection that contains the values in the read-only dictionary.
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values { get; }
Returns
- IEnumerable<TValue>
An enumerable collection that contains the values in the read-only dictionary.
ICollection.CopyTo(Array, int)
Copies the elements of the ICollection to an Array, starting at a particular Array index.
void ICollection.CopyTo(Array array, int index)
Parameters
arrayArrayThe one-dimensional Array that is the destination of the elements copied from ICollection. The Array must have zero-based indexing.
indexintThe zero-based index in
arrayat which copying begins.
Exceptions
- ArgumentNullException
arrayis null.- ArgumentOutOfRangeException
indexis less than zero.- ArgumentException
arrayis multidimensional.-or-
The number of elements in the source ICollection is greater than the available space from
indexto the end of the destinationarray.-or-
The type of the source ICollection cannot be cast automatically to the type of the destination
array.
ICollection.IsSynchronized
Gets a value indicating whether access to the ICollection is synchronized (thread safe).
bool ICollection.IsSynchronized { get; }
Returns
- bool
true if access to the ICollection is synchronized (thread safe); otherwise, false.
ICollection.SyncRoot
Gets an object that can be used to synchronize access to the ICollection.
object ICollection.SyncRoot { get; }
Returns
- object
An object that can be used to synchronize access to the ICollection.
IDictionary.Add(object, object)
Adds an element with the provided key and value to the IDictionary object.
void IDictionary.Add(object key, object value)
Parameters
keyobjectThe object to use as the key of the element to add.
valueobjectThe object to use as the value of the element to add.
Exceptions
- ArgumentNullException
keyis null.- ArgumentException
An element with the same key already exists in the IDictionary object.
- NotSupportedException
The IDictionary is read-only.
-or-
The IDictionary has a fixed size.
IDictionary.Contains(object)
Determines whether the IDictionary object contains an element with the specified key.
bool IDictionary.Contains(object key)
Parameters
keyobjectThe key to locate in the IDictionary object.
Returns
- bool
true if the IDictionary contains an element with the key; otherwise, false.
Exceptions
- ArgumentNullException
keyis null.
IDictionary.GetEnumerator()
Returns an IDictionaryEnumerator object for the IDictionary object.
IDictionaryEnumerator IDictionary.GetEnumerator()
Returns
- IDictionaryEnumerator
An IDictionaryEnumerator object for the IDictionary object.
IDictionary.IsFixedSize
Gets a value indicating whether the IDictionary object has a fixed size.
bool IDictionary.IsFixedSize { get; }
Returns
- bool
true if the IDictionary object has a fixed size; otherwise, false.
IDictionary.IsReadOnly
Gets a value indicating whether the IDictionary object is read-only.
bool IDictionary.IsReadOnly { get; }
Returns
- bool
true if the IDictionary object is read-only; otherwise, false.
IDictionary.Item[object]
Gets or sets the element with the specified key.
object? IDictionary.Item[object key] { get; set; }
Parameters
keyobjectThe key of the element to get or set.
Returns
Remarks
Following the Dictionary<TKey, TValue> contract for this[object], the getter throws ArgumentNullException for a null key and returns null for a non-null key of an incompatible type.
Exceptions
- ArgumentNullException
keyis null.- NotSupportedException
The property is set and the IDictionary object is read-only.
-or-
The property is set,
keydoes not exist in the collection, and the IDictionary has a fixed size.
IDictionary.Keys
Gets an ICollection object containing the keys of the IDictionary object.
ICollection IDictionary.Keys { get; }
Returns
- ICollection
An ICollection object containing the keys of the IDictionary object.
IDictionary.Remove(object)
Removes the element with the specified key from the IDictionary object.
void IDictionary.Remove(object key)
Parameters
keyobjectThe key of the element to remove.
Exceptions
- ArgumentNullException
keyis null.- NotSupportedException
The IDictionary object is read-only.
-or-
The IDictionary has a fixed size.
IDictionary.Values
Gets an ICollection object containing the values in the IDictionary object.
ICollection IDictionary.Values { get; }
Returns
- ICollection
An ICollection object containing the values in the IDictionary object.
IDictionary.get_Item(object)
object IDictionary.get_Item(object key)
Parameters
keyobject
Returns
IDictionary.set_Item(object, object)
void IDictionary.set_Item(object key, object value)
Parameters
IEnumerable.GetEnumerator()
Returns an enumerator that iterates through a collection.
IEnumerator IEnumerable.GetEnumerator()
Returns
- IEnumerator
An IEnumerator object that can be used to iterate through the collection.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |