Search code examples
c#dictionaryienumerablebidirectional

Use collection initializer for BiDirection dictionary


About BiDirection dictionary: Bidirectional 1 to 1 Dictionary in C#

My bi-dictionary is:

    internal class BiDirectionContainer<T1, T2>
    {
        private readonly Dictionary<T1, T2> _forward = new Dictionary<T1, T2>();
        private readonly Dictionary<T2, T1> _reverse = new Dictionary<T2, T1>();

        internal T2 this[T1 key] => _forward[key];

        internal T1 this[T2 key] => _reverse[key];

        internal void Add(T1 element1, T2 element2)
        {
            _forward.Add(element1, element2);
            _reverse.Add(element2, element1);
        }
    }

I want to add elements like this:

BiDirectionContainer<string, int> container = new BiDirectionContainer<string, int>
{
    {"111", 1},
    {"222", 2},
    {"333", 3},    
}

But im not sure if it right to use IEnumerable in BiDirectionContainer? What should i return if so? Is there any other way to implement such functionality?


Solution

  • The easiest is probably to enumerate the elements of the forward (or backward, whatever seems more natural) dictionary like so:

    internal class BiDirectionContainer<T1, T2> : IEnumerable<KeyValuePair<T1, T2>>
    {
        private readonly Dictionary<T1, T2> _forward = new Dictionary<T1, T2>();
        private readonly Dictionary<T2, T1> _reverse = new Dictionary<T2, T1>();
    
        internal T2 this[T1 key] => _forward[key];
    
        internal T1 this[T2 key] => _reverse[key];
    
        IEnumerator<KeyValuePair<T1, T2>> IEnumerable<KeyValuePair<T1, T2>>.GetEnumerator()
        {
            return _forward.GetEnumerator();
        }
    
        public IEnumerator GetEnumerator()
        {
            return _forward.GetEnumerator();
        }
    
        internal void Add(T1 element1, T2 element2)
        {
            _forward.Add(element1, element2);
            _reverse.Add(element2, element1);
        }
    }
    

    As an aside: If you only want to be able to use collection initializer, it is required by the C# language specification that your class implements System.Collections.IEnumerable and also provides an Add method that is applicable for each element initializer (i.e. basically number and type of arguments must match). The interface is required by the compiler, but the GetEnumerator method is not called when the collection is initialized (only the add method is). It is required because the collection initializer should only be available for things that actually are a collection and not just something that has an add method. Therefore it is fine to just add the interface without actually implementing a method body (public IEnumerator GetEnumerator(){ throw new NotImplementedException(); })