Table of Contents

BiDictionary<TKey, TValue> Class

Definition

Namespace
Bodu.Collections.Generic
Assembly
Bodu.Collections.dll
Package
Bodu.Collections 1.0.0
Source
BiDictionary{T,T}.ICollection.cs

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

TKey

Specifies the type of keys in the dictionary.

TValue

Specifies the type of values in the dictionary.

Inheritance
BiDictionary<TKey, TValue>
Implements
IDictionary<TKey, TValue>
ICollection<KeyValuePair<TKey, TValue>>
IReadOnlyDictionary<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

duplicateValuePolicy BiDictionaryDuplicateValuePolicy

The policy applied when an add or assignment operation supplies a value already bound to a different key.

Exceptions

ArgumentOutOfRangeException

duplicateValuePolicy is 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

duplicateValuePolicy BiDictionaryDuplicateValuePolicy

The policy applied when an add or assignment operation supplies a value already bound to a different key.

keyComparer IEqualityComparer<TKey>

The equality comparer to use for keys, or null to use the default comparer.

valueComparer IEqualityComparer<TValue>

The equality comparer to use for values, or null to use the default comparer.

Exceptions

ArgumentOutOfRangeException

duplicateValuePolicy is 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

duplicateValuePolicy BiDictionaryDuplicateValuePolicy

The policy applied when an add or assignment operation supplies a value already bound to a different key.

capacity int

The initial number of entries the internal hash tables can hold without resizing.

Exceptions

ArgumentOutOfRangeException

duplicateValuePolicy is not a defined BiDictionaryDuplicateValuePolicy value, or capacity is 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

duplicateValuePolicy BiDictionaryDuplicateValuePolicy

The policy applied when an add or assignment operation supplies a value already bound to a different key.

capacity int

The initial number of entries the internal hash tables can hold without resizing.

keyComparer IEqualityComparer<TKey>

The equality comparer to use for keys, or null to use the default comparer.

valueComparer IEqualityComparer<TValue>

The equality comparer to use for values, or null to use the default comparer.

Exceptions

ArgumentOutOfRangeException

duplicateValuePolicy is not a defined BiDictionaryDuplicateValuePolicy value, or capacity is 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

keyComparer IEqualityComparer<TKey>

The equality comparer to use for keys, or null to use the default comparer.

valueComparer IEqualityComparer<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

capacity int

The initial number of entries the internal hash tables can hold without resizing.

Exceptions

ArgumentOutOfRangeException

capacity is 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

capacity int

The initial number of entries the internal hash tables can hold without resizing.

keyComparer IEqualityComparer<TKey>

The equality comparer to use for keys, or null to use the default comparer.

valueComparer IEqualityComparer<TValue>

The equality comparer to use for values, or null to use the default comparer.

Exceptions

ArgumentOutOfRangeException

capacity is 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

key TKey

The 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

key is null.

KeyNotFoundException

The property is retrieved and key is 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

item KeyValuePair<TKey, TValue>

The key/value pair to add to the dictionary.

Exceptions

ArgumentNullException

item.Key or item.Value is 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

key TKey

The key of the element to add. Must not be null.

value TValue

The 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

key or value is null.

ArgumentException

An element with the same key already exists in the dictionary, or value is 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

item KeyValuePair<TKey, TValue>

The object to locate in the ICollection<T>.

Returns

bool

true if item is 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

key TKey

The 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

key is null.

ContainsValue(TValue)

Determines whether the dictionary contains a specific value.

public bool ContainsValue(TValue value)

Parameters

value TValue

The value to locate. Must not be null.

Returns

bool

true if a key is bound to value; otherwise, false.

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

value is 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

array KeyValuePair<TKey, TValue>[]

The one-dimensional Array that is the destination of the elements copied from ICollection<T>. The Array must have zero-based indexing.

arrayIndex int

The zero-based index in array at which copying begins.

Exceptions

ArgumentNullException

array is null.

ArgumentOutOfRangeException

arrayIndex is less than 0.

ArgumentException

The number of elements in the source ICollection<T> is greater than the available space from arrayIndex to the end of the destination array.

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

item KeyValuePair<TKey, TValue>

The object to remove from the ICollection<T>.

Returns

bool

true if item was successfully removed from the ICollection<T>; otherwise, false. This method also returns false if item is 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

key TKey

The key of the element to remove.

Returns

bool

true if the element is successfully removed; otherwise, false. This method also returns false if key was 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

key is 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

value TValue

The value of the pair to remove. Must not be null.

Returns

bool

true if a pair was found and removed; otherwise, false.

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

value is 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

key TKey

The key of the element to add. Must not be null.

value TValue

The 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

key or value is null.

TryGetKey(TValue, out TKey)

Attempts to retrieve the key bound to the specified value.

public bool TryGetKey(TValue value, out TKey key)

Parameters

value TValue

The value whose key to retrieve. Must not be null.

key TKey

When 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

bool

true if a key is bound to value; otherwise, false.

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

value is null.

TryGetValue(TKey, out TValue)

Attempts to retrieve the value bound to the specified key.

public bool TryGetValue(TKey key, out TValue value)

Parameters

key TKey

The key of the value to retrieve. Must not be null.

value TValue

When 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

bool

true if the dictionary contains an element with the specified key; otherwise, false.

Exceptions

ArgumentNullException

key is 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

array Array

The one-dimensional Array that is the destination of the elements copied from ICollection. The Array must have zero-based indexing.

index int

The zero-based index in array at which copying begins.

Exceptions

ArgumentNullException

array is null.

ArgumentOutOfRangeException

index is less than zero.

ArgumentException

array is multidimensional.

-or-

The number of elements in the source ICollection is greater than the available space from index to the end of the destination array.

-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

key object

The object to use as the key of the element to add.

value object

The object to use as the value of the element to add.

Exceptions

ArgumentNullException

key is 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

key object

The key to locate in the IDictionary object.

Returns

bool

true if the IDictionary contains an element with the key; otherwise, false.

Exceptions

ArgumentNullException

key is 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

key object

The key of the element to get or set.

Returns

object

The element with the specified key, or null if the key does not exist.

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

key is null.

NotSupportedException

The property is set and the IDictionary object is read-only.

-or-

The property is set, key does 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

key object

The key of the element to remove.

Exceptions

ArgumentNullException

key is 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

key object

Returns

object

IDictionary.set_Item(object, object)

void IDictionary.set_Item(object key, object value)

Parameters

key object
value object

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

ProductVersions
.NET8, 10