Normalize all C# and .proto files to LF

This commit should have no non-whitespace changes

Fixes #9526 (in terms of content)
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
index 6b7d0f1..e5217f4 100644
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -1,762 +1,762 @@
-#region Copyright notice and license

-// Protocol Buffers - Google's data interchange format

-// Copyright 2015 Google Inc.  All rights reserved.

-// https://developers.google.com/protocol-buffers/

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-#endregion

-

-using Google.Protobuf.Compatibility;

-using Google.Protobuf.Reflection;

-using System;

-using System.Buffers;

-using System.Collections;

-using System.Collections.Generic;

-using System.IO;

-using System.Linq;

-using System.Security;

-

-namespace Google.Protobuf.Collections

-{

-    /// <summary>

-    /// Representation of a map field in a Protocol Buffer message.

-    /// </summary>

-    /// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>

-    /// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>

-    /// <remarks>

-    /// <para>

-    /// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.

-    /// </para>

-    /// <para>

-    /// Null values are not permitted in the map, either for wrapper types or regular messages.

-    /// If a map is deserialized from a data stream and the value is missing from an entry, a default value

-    /// is created instead. For primitive types, that is the regular default value (0, the empty string and so

-    /// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length

-    /// encoded value for the field.

-    /// </para>

-    /// <para>

-    /// This implementation does not generally prohibit the use of key/value types which are not

-    /// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee

-    /// that all operations will work in such cases.

-    /// </para>

-    /// <para>

-    /// The order in which entries are returned when iterating over this object is undefined, and may change

-    /// in future versions.

-    /// </para>

-    /// </remarks>

-    public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary

-#if !NET35

-        , IReadOnlyDictionary<TKey, TValue>

-#endif

-    {

-        private static readonly EqualityComparer<TValue> ValueEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TValue>();

-        private static readonly EqualityComparer<TKey> KeyEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TKey>();

-

-        // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)

-        private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =

-            new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(KeyEqualityComparer);

-        private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();

-

-        /// <summary>

-        /// Creates a deep clone of this object.

-        /// </summary>

-        /// <returns>

-        /// A deep clone of this object.

-        /// </returns>

-        public MapField<TKey, TValue> Clone()

-        {

-            var clone = new MapField<TKey, TValue>();

-            // Keys are never cloneable. Values might be.

-            if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))

-            {

-                foreach (var pair in list)

-                {

-                    clone.Add(pair.Key, ((IDeepCloneable<TValue>)pair.Value).Clone());

-                }

-            }

-            else

-            {

-                // Nothing is cloneable, so we don't need to worry.

-                clone.Add(this);

-            }

-            return clone;

-        }

-

-        /// <summary>

-        /// Adds the specified key/value pair to the map.

-        /// </summary>

-        /// <remarks>

-        /// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer.

-        /// </remarks>

-        /// <param name="key">The key to add</param>

-        /// <param name="value">The value to add.</param>

-        /// <exception cref="System.ArgumentException">The given key already exists in map.</exception>

-        public void Add(TKey key, TValue value)

-        {

-            // Validation of arguments happens in ContainsKey and the indexer

-            if (ContainsKey(key))

-            {

-                throw new ArgumentException("Key already exists in map", nameof(key));

-            }

-            this[key] = value;

-        }

-

-        /// <summary>

-        /// Determines whether the specified key is present in the map.

-        /// </summary>

-        /// <param name="key">The key to check.</param>

-        /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>

-        public bool ContainsKey(TKey key)

-        {

-            ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));

-            return map.ContainsKey(key);

-        }

-

-        private bool ContainsValue(TValue value) =>

-            list.Any(pair => ValueEqualityComparer.Equals(pair.Value, value));

-

-        /// <summary>

-        /// Removes the entry identified by the given key from the map.

-        /// </summary>

-        /// <param name="key">The key indicating the entry to remove from the map.</param>

-        /// <returns><c>true</c> if the map contained the given key before the entry was removed; <c>false</c> otherwise.</returns>

-        public bool Remove(TKey key)

-        {

-            ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));

-            LinkedListNode<KeyValuePair<TKey, TValue>> node;

-            if (map.TryGetValue(key, out node))

-            {

-                map.Remove(key);

-                node.List.Remove(node);

-                return true;

-            }

-            else

-            {

-                return false;

-            }

-        }

-

-        /// <summary>

-        /// Gets the value associated with the specified key.

-        /// </summary>

-        /// <param name="key">The key whose value to get.</param>

-        /// <param name="value">When this method returns, the value associated with the specified key, if the key is found;

-        /// otherwise, the default value for the type of the <paramref name="value"/> parameter.

-        /// This parameter is passed uninitialized.</param>

-        /// <returns><c>true</c> if the map contains an element with the specified key; otherwise, <c>false</c>.</returns>

-        public bool TryGetValue(TKey key, out TValue value)

-        {

-            LinkedListNode<KeyValuePair<TKey, TValue>> node;

-            if (map.TryGetValue(key, out node))

-            {

-                value = node.Value.Value;

-                return true;

-            }

-            else

-            {

-                value = default(TValue);

-                return false;

-            }

-        }

-

-        /// <summary>

-        /// Gets or sets the value associated with the specified key.

-        /// </summary>

-        /// <param name="key">The key of the value to get or set.</param>

-        /// <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>

-        /// <returns>The value associated with the specified key. If the specified key is not found,

-        /// a get operation throws a <see cref="KeyNotFoundException"/>, and a set operation creates a new element with the specified key.</returns>

-        public TValue this[TKey key]

-        {

-            get

-            {

-                ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));

-                TValue value;

-                if (TryGetValue(key, out value))

-                {

-                    return value;

-                }

-                throw new KeyNotFoundException();

-            }

-            set

-            {

-                ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));

-                // value == null check here is redundant, but avoids boxing.

-                if (value == null)

-                {

-                    ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));

-                }

-                LinkedListNode<KeyValuePair<TKey, TValue>> node;

-                var pair = new KeyValuePair<TKey, TValue>(key, value);

-                if (map.TryGetValue(key, out node))

-                {

-                    node.Value = pair;

-                }

-                else

-                {

-                    node = list.AddLast(pair);

-                    map[key] = node;

-                }

-            }

-        }

-

-        /// <summary>

-        /// Gets a collection containing the keys in the map.

-        /// </summary>

-        public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pair => pair.Key, ContainsKey); } }

-

-        /// <summary>

-        /// Gets a collection containing the values in the map.

-        /// </summary>

-        public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }

-

-        /// <summary>

-        /// Adds the specified entries to the map. The keys and values are not automatically cloned.

-        /// </summary>

-        /// <param name="entries">The entries to add to the map.</param>

-        public void Add(IDictionary<TKey, TValue> entries)

-        {

-            ProtoPreconditions.CheckNotNull(entries, nameof(entries));

-            foreach (var pair in entries)

-            {

-                Add(pair.Key, pair.Value);

-            }

-        }

-

-        /// <summary>

-        /// Returns an enumerator that iterates through the collection.

-        /// </summary>

-        /// <returns>

-        /// An enumerator that can be used to iterate through the collection.

-        /// </returns>

-        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()

-        {

-            return list.GetEnumerator();

-        }

-

-        /// <summary>

-        /// Returns an enumerator that iterates through a collection.

-        /// </summary>

-        /// <returns>

-        /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.

-        /// </returns>

-        IEnumerator IEnumerable.GetEnumerator()

-        {

-            return GetEnumerator();

-        }

-

-        /// <summary>

-        /// Adds the specified item to the map.

-        /// </summary>

-        /// <param name="item">The item to add to the map.</param>

-        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)

-        {

-            Add(item.Key, item.Value);

-        }

-

-        /// <summary>

-        /// Removes all items from the map.

-        /// </summary>

-        public void Clear()

-        {

-            list.Clear();

-            map.Clear();

-        }

-

-        /// <summary>

-        /// Determines whether map contains an entry equivalent to the given key/value pair.

-        /// </summary>

-        /// <param name="item">The key/value pair to find.</param>

-        /// <returns></returns>

-        bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)

-        {

-            TValue value;

-            return TryGetValue(item.Key, out value) && ValueEqualityComparer.Equals(item.Value, value);

-        }

-

-        /// <summary>

-        /// Copies the key/value pairs in this map to an array.

-        /// </summary>

-        /// <param name="array">The array to copy the entries into.</param>

-        /// <param name="arrayIndex">The index of the array at which to start copying values.</param>

-        void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)

-        {

-            list.CopyTo(array, arrayIndex);

-        }

-

-        /// <summary>

-        /// Removes the specified key/value pair from the map.

-        /// </summary>

-        /// <remarks>Both the key and the value must be found for the entry to be removed.</remarks>

-        /// <param name="item">The key/value pair to remove.</param>

-        /// <returns><c>true</c> if the key/value pair was found and removed; <c>false</c> otherwise.</returns>

-        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)

-        {

-            if (item.Key == null)

-            {

-                throw new ArgumentException("Key is null", nameof(item));

-            }

-            LinkedListNode<KeyValuePair<TKey, TValue>> node;

-            if (map.TryGetValue(item.Key, out node) &&

-                EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.Value))

-            {

-                map.Remove(item.Key);

-                node.List.Remove(node);

-                return true;

-            }

-            else

-            {

-                return false;

-            }

-        }

-

-        /// <summary>

-        /// Gets the number of elements contained in the map.

-        /// </summary>

-        public int Count { get { return list.Count; } }

-

-        /// <summary>

-        /// Gets a value indicating whether the map is read-only.

-        /// </summary>

-        public bool IsReadOnly { get { return false; } }

-

-        /// <summary>

-        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.

-        /// </summary>

-        /// <param name="other">The <see cref="System.Object" /> to compare with this instance.</param>

-        /// <returns>

-        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.

-        /// </returns>

-        public override bool Equals(object other)

-        {

-            return Equals(other as MapField<TKey, TValue>);

-        }

-

-        /// <summary>

-        /// Returns a hash code for this instance.

-        /// </summary>

-        /// <returns>

-        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 

-        /// </returns>

-        public override int GetHashCode()

-        {

-            var keyComparer = KeyEqualityComparer;

-            var valueComparer = ValueEqualityComparer;

-            int hash = 0;

-            foreach (var pair in list)

-            {

-                hash ^= keyComparer.GetHashCode(pair.Key) * 31 + valueComparer.GetHashCode(pair.Value);

-            }

-            return hash;

-        }

-

-        /// <summary>

-        /// Compares this map with another for equality.

-        /// </summary>

-        /// <remarks>

-        /// The order of the key/value pairs in the maps is not deemed significant in this comparison.

-        /// </remarks>

-        /// <param name="other">The map to compare this with.</param>

-        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal map; <c>false</c> otherwise.</returns>

-        public bool Equals(MapField<TKey, TValue> other)

-        {

-            if (other == null)

-            {

-                return false;

-            }

-            if (other == this)

-            {

-                return true;

-            }

-            if (other.Count != this.Count)

-            {

-                return false;

-            }

-            var valueComparer = ValueEqualityComparer;

-            foreach (var pair in this)

-            {

-                TValue value;

-                if (!other.TryGetValue(pair.Key, out value))

-                {

-                    return false;

-                }

-                if (!valueComparer.Equals(value, pair.Value))

-                {

-                    return false;

-                }

-            }

-            return true;

-        }

-

-        /// <summary>

-        /// Adds entries to the map from the given stream.

-        /// </summary>

-        /// <remarks>

-        /// It is assumed that the stream is initially positioned after the tag specified by the codec.

-        /// This method will continue reading entries from the stream until the end is reached, or

-        /// a different tag is encountered.

-        /// </remarks>

-        /// <param name="input">Stream to read from</param>

-        /// <param name="codec">Codec describing how the key/value pairs are encoded</param>

-        public void AddEntriesFrom(CodedInputStream input, Codec codec)

-        {

-            ParseContext.Initialize(input, out ParseContext ctx);

-            try

-            {

-                AddEntriesFrom(ref ctx, codec);

-            }

-            finally

-            {

-                ctx.CopyStateTo(input);

-            }

-        }

-

-        /// <summary>

-        /// Adds entries to the map from the given parse context.

-        /// </summary>

-        /// <remarks>

-        /// It is assumed that the input is initially positioned after the tag specified by the codec.

-        /// This method will continue reading entries from the input until the end is reached, or

-        /// a different tag is encountered.

-        /// </remarks>

-        /// <param name="ctx">Input to read from</param>

-        /// <param name="codec">Codec describing how the key/value pairs are encoded</param>

-        [SecuritySafeCritical]

-        public void AddEntriesFrom(ref ParseContext ctx, Codec codec)

-        {

-            do

-            {

-                KeyValuePair<TKey, TValue> entry = ParsingPrimitivesMessages.ReadMapEntry(ref ctx, codec);

-                this[entry.Key] = entry.Value;

-            } while (ParsingPrimitives.MaybeConsumeTag(ref ctx.buffer, ref ctx.state, codec.MapTag));

-        }

-

-        /// <summary>

-        /// Writes the contents of this map to the given coded output stream, using the specified codec

-        /// to encode each entry.

-        /// </summary>

-        /// <param name="output">The output stream to write to.</param>

-        /// <param name="codec">The codec to use for each entry.</param>

-        public void WriteTo(CodedOutputStream output, Codec codec)

-        {

-            WriteContext.Initialize(output, out WriteContext ctx);

-            try

-            {

-                WriteTo(ref ctx, codec);

-            }

-            finally

-            {

-                ctx.CopyStateTo(output);

-            }

-        }

-

-        /// <summary>

-        /// Writes the contents of this map to the given write context, using the specified codec

-        /// to encode each entry.

-        /// </summary>

-        /// <param name="ctx">The write context to write to.</param>

-        /// <param name="codec">The codec to use for each entry.</param>

-        [SecuritySafeCritical]

-        public void WriteTo(ref WriteContext ctx, Codec codec)

-        {

-            foreach (var entry in list)

-            {

-                ctx.WriteTag(codec.MapTag);

-

-                WritingPrimitives.WriteLength(ref ctx.buffer, ref ctx.state, CalculateEntrySize(codec, entry));

-                codec.KeyCodec.WriteTagAndValue(ref ctx, entry.Key);

-                codec.ValueCodec.WriteTagAndValue(ref ctx, entry.Value);

-            }

-        }

-

-        /// <summary>

-        /// Calculates the size of this map based on the given entry codec.

-        /// </summary>

-        /// <param name="codec">The codec to use to encode each entry.</param>

-        /// <returns></returns>

-        public int CalculateSize(Codec codec)

-        {

-            if (Count == 0)

-            {

-                return 0;

-            }

-            int size = 0;

-            foreach (var entry in list)

-            {

-                int entrySize = CalculateEntrySize(codec, entry);

-

-                size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);

-                size += CodedOutputStream.ComputeLengthSize(entrySize) + entrySize;

-            }

-            return size;

-        }

-

-        private static int CalculateEntrySize(Codec codec, KeyValuePair<TKey, TValue> entry)

-        {

-            return codec.KeyCodec.CalculateSizeWithTag(entry.Key) + codec.ValueCodec.CalculateSizeWithTag(entry.Value);

-        }

-

-        /// <summary>

-        /// Returns a string representation of this repeated field, in the same

-        /// way as it would be represented by the default JSON formatter.

-        /// </summary>

-        public override string ToString()

-        {

-            var writer = new StringWriter();

-            JsonFormatter.Default.WriteDictionary(writer, this);

-            return writer.ToString();

-        }

-

-        #region IDictionary explicit interface implementation

-        void IDictionary.Add(object key, object value)

-        {

-            Add((TKey)key, (TValue)value);

-        }

-

-        bool IDictionary.Contains(object key)

-        {

-            if (!(key is TKey))

-            {

-                return false;

-            }

-            return ContainsKey((TKey)key);

-        }

-

-        IDictionaryEnumerator IDictionary.GetEnumerator()

-        {

-            return new DictionaryEnumerator(GetEnumerator());

-        }

-

-        void IDictionary.Remove(object key)

-        {

-            ProtoPreconditions.CheckNotNull(key, nameof(key));

-            if (!(key is TKey))

-            {

-                return;

-            }

-            Remove((TKey)key);

-        }

-

-        void ICollection.CopyTo(Array array, int index)

-        {

-            // This is ugly and slow as heck, but with any luck it will never be used anyway.

-            ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();

-            temp.CopyTo(array, index);

-        }

-

-        bool IDictionary.IsFixedSize { get { return false; } }

-

-        ICollection IDictionary.Keys { get { return (ICollection)Keys; } }

-

-        ICollection IDictionary.Values { get { return (ICollection)Values; } }

-

-        bool ICollection.IsSynchronized { get { return false; } }

-

-        object ICollection.SyncRoot { get { return this; } }

-

-        object IDictionary.this[object key]

-        {

-            get

-            {

-                ProtoPreconditions.CheckNotNull(key, nameof(key));

-                if (!(key is TKey))

-                {

-                    return null;

-                }

-                TValue value;

-                TryGetValue((TKey)key, out value);

-                return value;

-            }

-

-            set

-            {

-                this[(TKey)key] = (TValue)value;

-            }

-        }

-        #endregion

-

-        #region IReadOnlyDictionary explicit interface implementation

-#if !NET35

-        IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;

-

-        IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;

-#endif

-        #endregion

-

-        private class DictionaryEnumerator : IDictionaryEnumerator

-        {

-            private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;

-

-            internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)

-            {

-                this.enumerator = enumerator;

-            }

-

-            public bool MoveNext()

-            {

-                return enumerator.MoveNext();

-            }

-

-            public void Reset()

-            {

-                enumerator.Reset();

-            }

-

-            public object Current { get { return Entry; } }

-            public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }

-            public object Key { get { return enumerator.Current.Key; } }

-            public object Value { get { return enumerator.Current.Value; } }

-        }

-

-        /// <summary>

-        /// A codec for a specific map field. This contains all the information required to encode and

-        /// decode the nested messages.

-        /// </summary>

-        public sealed class Codec

-        {

-            private readonly FieldCodec<TKey> keyCodec;

-            private readonly FieldCodec<TValue> valueCodec;

-            private readonly uint mapTag;

-

-            /// <summary>

-            /// Creates a new entry codec based on a separate key codec and value codec,

-            /// and the tag to use for each map entry.

-            /// </summary>

-            /// <param name="keyCodec">The key codec.</param>

-            /// <param name="valueCodec">The value codec.</param>

-            /// <param name="mapTag">The map tag to use to introduce each map entry.</param>

-            public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCodec, uint mapTag)

-            {

-                this.keyCodec = keyCodec;

-                this.valueCodec = valueCodec;

-                this.mapTag = mapTag;

-            }

-

-            /// <summary>

-            /// The key codec.

-            /// </summary>

-            internal FieldCodec<TKey> KeyCodec => keyCodec;

-

-            /// <summary>

-            /// The value codec.

-            /// </summary>

-            internal FieldCodec<TValue> ValueCodec => valueCodec;

-

-            /// <summary>

-            /// The tag used in the enclosing message to indicate map entries.

-            /// </summary>

-            internal uint MapTag => mapTag;

-        }

-

-        private class MapView<T> : ICollection<T>, ICollection

-        {

-            private readonly MapField<TKey, TValue> parent;

-            private readonly Func<KeyValuePair<TKey, TValue>, T> projection;

-            private readonly Func<T, bool> containsCheck;

-

-            internal MapView(

-                MapField<TKey, TValue> parent,

-                Func<KeyValuePair<TKey, TValue>, T> projection,

-                Func<T, bool> containsCheck)

-            {

-                this.parent = parent;

-                this.projection = projection;

-                this.containsCheck = containsCheck;

-            }

-

-            public int Count { get { return parent.Count; } }

-

-            public bool IsReadOnly { get { return true; } }

-

-            public bool IsSynchronized { get { return false; } }

-

-            public object SyncRoot { get { return parent; } }

-

-            public void Add(T item)

-            {

-                throw new NotSupportedException();

-            }

-

-            public void Clear()

-            {

-                throw new NotSupportedException();

-            }

-

-            public bool Contains(T item)

-            {

-                return containsCheck(item);

-            }

-

-            public void CopyTo(T[] array, int arrayIndex)

-            {

-                if (arrayIndex < 0)

-                {

-                    throw new ArgumentOutOfRangeException(nameof(arrayIndex));

-                }

-                if (arrayIndex + Count > array.Length)

-                {

-                    throw new ArgumentException("Not enough space in the array", nameof(array));

-                }

-                foreach (var item in this)

-                {

-                    array[arrayIndex++] = item;

-                }

-            }

-

-            public IEnumerator<T> GetEnumerator()

-            {

-                return parent.list.Select(projection).GetEnumerator();

-            }

-

-            public bool Remove(T item)

-            {

-                throw new NotSupportedException();

-            }

-

-            IEnumerator IEnumerable.GetEnumerator()

-            {

-                return GetEnumerator();

-            }

-

-            public void CopyTo(Array array, int index)

-            {

-                if (index < 0)

-                {

-                    throw new ArgumentOutOfRangeException(nameof(index));

-                }

-                if (index + Count > array.Length)

-                {

-                    throw new ArgumentException("Not enough space in the array", nameof(array));

-                }

-                foreach (var item in this)

-                {

-                    array.SetValue(item, index++);

-                }

-            }

-        }

-    }

-}

+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Compatibility;
+using Google.Protobuf.Reflection;
+using System;
+using System.Buffers;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security;
+
+namespace Google.Protobuf.Collections
+{
+    /// <summary>
+    /// Representation of a map field in a Protocol Buffer message.
+    /// </summary>
+    /// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
+    /// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
+    /// <remarks>
+    /// <para>
+    /// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.
+    /// </para>
+    /// <para>
+    /// Null values are not permitted in the map, either for wrapper types or regular messages.
+    /// If a map is deserialized from a data stream and the value is missing from an entry, a default value
+    /// is created instead. For primitive types, that is the regular default value (0, the empty string and so
+    /// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
+    /// encoded value for the field.
+    /// </para>
+    /// <para>
+    /// This implementation does not generally prohibit the use of key/value types which are not
+    /// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
+    /// that all operations will work in such cases.
+    /// </para>
+    /// <para>
+    /// The order in which entries are returned when iterating over this object is undefined, and may change
+    /// in future versions.
+    /// </para>
+    /// </remarks>
+    public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
+#if !NET35
+        , IReadOnlyDictionary<TKey, TValue>
+#endif
+    {
+        private static readonly EqualityComparer<TValue> ValueEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TValue>();
+        private static readonly EqualityComparer<TKey> KeyEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TKey>();
+
+        // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
+        private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
+            new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(KeyEqualityComparer);
+        private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
+
+        /// <summary>
+        /// Creates a deep clone of this object.
+        /// </summary>
+        /// <returns>
+        /// A deep clone of this object.
+        /// </returns>
+        public MapField<TKey, TValue> Clone()
+        {
+            var clone = new MapField<TKey, TValue>();
+            // Keys are never cloneable. Values might be.
+            if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
+            {
+                foreach (var pair in list)
+                {
+                    clone.Add(pair.Key, ((IDeepCloneable<TValue>)pair.Value).Clone());
+                }
+            }
+            else
+            {
+                // Nothing is cloneable, so we don't need to worry.
+                clone.Add(this);
+            }
+            return clone;
+        }
+
+        /// <summary>
+        /// Adds the specified key/value pair to the map.
+        /// </summary>
+        /// <remarks>
+        /// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer.
+        /// </remarks>
+        /// <param name="key">The key to add</param>
+        /// <param name="value">The value to add.</param>
+        /// <exception cref="System.ArgumentException">The given key already exists in map.</exception>
+        public void Add(TKey key, TValue value)
+        {
+            // Validation of arguments happens in ContainsKey and the indexer
+            if (ContainsKey(key))
+            {
+                throw new ArgumentException("Key already exists in map", nameof(key));
+            }
+            this[key] = value;
+        }
+
+        /// <summary>
+        /// Determines whether the specified key is present in the map.
+        /// </summary>
+        /// <param name="key">The key to check.</param>
+        /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
+        public bool ContainsKey(TKey key)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
+            return map.ContainsKey(key);
+        }
+
+        private bool ContainsValue(TValue value) =>
+            list.Any(pair => ValueEqualityComparer.Equals(pair.Value, value));
+
+        /// <summary>
+        /// Removes the entry identified by the given key from the map.
+        /// </summary>
+        /// <param name="key">The key indicating the entry to remove from the map.</param>
+        /// <returns><c>true</c> if the map contained the given key before the entry was removed; <c>false</c> otherwise.</returns>
+        public bool Remove(TKey key)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(key, out node))
+            {
+                map.Remove(key);
+                node.List.Remove(node);
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets the value associated with the specified key.
+        /// </summary>
+        /// <param name="key">The key whose value to get.</param>
+        /// <param name="value">When this method returns, the value associated with the specified key, if the key is found;
+        /// otherwise, the default value for the type of the <paramref name="value"/> parameter.
+        /// This parameter is passed uninitialized.</param>
+        /// <returns><c>true</c> if the map contains an element with the specified key; otherwise, <c>false</c>.</returns>
+        public bool TryGetValue(TKey key, out TValue value)
+        {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(key, out node))
+            {
+                value = node.Value.Value;
+                return true;
+            }
+            else
+            {
+                value = default(TValue);
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the value associated with the specified key.
+        /// </summary>
+        /// <param name="key">The key of the value to get or set.</param>
+        /// <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
+        /// <returns>The value associated with the specified key. If the specified key is not found,
+        /// a get operation throws a <see cref="KeyNotFoundException"/>, and a set operation creates a new element with the specified key.</returns>
+        public TValue this[TKey key]
+        {
+            get
+            {
+                ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
+                TValue value;
+                if (TryGetValue(key, out value))
+                {
+                    return value;
+                }
+                throw new KeyNotFoundException();
+            }
+            set
+            {
+                ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
+                // value == null check here is redundant, but avoids boxing.
+                if (value == null)
+                {
+                    ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));
+                }
+                LinkedListNode<KeyValuePair<TKey, TValue>> node;
+                var pair = new KeyValuePair<TKey, TValue>(key, value);
+                if (map.TryGetValue(key, out node))
+                {
+                    node.Value = pair;
+                }
+                else
+                {
+                    node = list.AddLast(pair);
+                    map[key] = node;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets a collection containing the keys in the map.
+        /// </summary>
+        public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pair => pair.Key, ContainsKey); } }
+
+        /// <summary>
+        /// Gets a collection containing the values in the map.
+        /// </summary>
+        public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
+
+        /// <summary>
+        /// Adds the specified entries to the map. The keys and values are not automatically cloned.
+        /// </summary>
+        /// <param name="entries">The entries to add to the map.</param>
+        public void Add(IDictionary<TKey, TValue> entries)
+        {
+            ProtoPreconditions.CheckNotNull(entries, nameof(entries));
+            foreach (var pair in entries)
+            {
+                Add(pair.Key, pair.Value);
+            }
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the collection.
+        /// </summary>
+        /// <returns>
+        /// An enumerator that can be used to iterate through the collection.
+        /// </returns>
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+        {
+            return list.GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through a collection.
+        /// </summary>
+        /// <returns>
+        /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
+        /// </returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Adds the specified item to the map.
+        /// </summary>
+        /// <param name="item">The item to add to the map.</param>
+        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
+        {
+            Add(item.Key, item.Value);
+        }
+
+        /// <summary>
+        /// Removes all items from the map.
+        /// </summary>
+        public void Clear()
+        {
+            list.Clear();
+            map.Clear();
+        }
+
+        /// <summary>
+        /// Determines whether map contains an entry equivalent to the given key/value pair.
+        /// </summary>
+        /// <param name="item">The key/value pair to find.</param>
+        /// <returns></returns>
+        bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
+        {
+            TValue value;
+            return TryGetValue(item.Key, out value) && ValueEqualityComparer.Equals(item.Value, value);
+        }
+
+        /// <summary>
+        /// Copies the key/value pairs in this map to an array.
+        /// </summary>
+        /// <param name="array">The array to copy the entries into.</param>
+        /// <param name="arrayIndex">The index of the array at which to start copying values.</param>
+        void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+        {
+            list.CopyTo(array, arrayIndex);
+        }
+
+        /// <summary>
+        /// Removes the specified key/value pair from the map.
+        /// </summary>
+        /// <remarks>Both the key and the value must be found for the entry to be removed.</remarks>
+        /// <param name="item">The key/value pair to remove.</param>
+        /// <returns><c>true</c> if the key/value pair was found and removed; <c>false</c> otherwise.</returns>
+        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
+        {
+            if (item.Key == null)
+            {
+                throw new ArgumentException("Key is null", nameof(item));
+            }
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(item.Key, out node) &&
+                EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.Value))
+            {
+                map.Remove(item.Key);
+                node.List.Remove(node);
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets the number of elements contained in the map.
+        /// </summary>
+        public int Count { get { return list.Count; } }
+
+        /// <summary>
+        /// Gets a value indicating whether the map is read-only.
+        /// </summary>
+        public bool IsReadOnly { get { return false; } }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
+        /// </summary>
+        /// <param name="other">The <see cref="System.Object" /> to compare with this instance.</param>
+        /// <returns>
+        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool Equals(object other)
+        {
+            return Equals(other as MapField<TKey, TValue>);
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public override int GetHashCode()
+        {
+            var keyComparer = KeyEqualityComparer;
+            var valueComparer = ValueEqualityComparer;
+            int hash = 0;
+            foreach (var pair in list)
+            {
+                hash ^= keyComparer.GetHashCode(pair.Key) * 31 + valueComparer.GetHashCode(pair.Value);
+            }
+            return hash;
+        }
+
+        /// <summary>
+        /// Compares this map with another for equality.
+        /// </summary>
+        /// <remarks>
+        /// The order of the key/value pairs in the maps is not deemed significant in this comparison.
+        /// </remarks>
+        /// <param name="other">The map to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
+        public bool Equals(MapField<TKey, TValue> other)
+        {
+            if (other == null)
+            {
+                return false;
+            }
+            if (other == this)
+            {
+                return true;
+            }
+            if (other.Count != this.Count)
+            {
+                return false;
+            }
+            var valueComparer = ValueEqualityComparer;
+            foreach (var pair in this)
+            {
+                TValue value;
+                if (!other.TryGetValue(pair.Key, out value))
+                {
+                    return false;
+                }
+                if (!valueComparer.Equals(value, pair.Value))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Adds entries to the map from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// It is assumed that the stream is initially positioned after the tag specified by the codec.
+        /// This method will continue reading entries from the stream until the end is reached, or
+        /// a different tag is encountered.
+        /// </remarks>
+        /// <param name="input">Stream to read from</param>
+        /// <param name="codec">Codec describing how the key/value pairs are encoded</param>
+        public void AddEntriesFrom(CodedInputStream input, Codec codec)
+        {
+            ParseContext.Initialize(input, out ParseContext ctx);
+            try
+            {
+                AddEntriesFrom(ref ctx, codec);
+            }
+            finally
+            {
+                ctx.CopyStateTo(input);
+            }
+        }
+
+        /// <summary>
+        /// Adds entries to the map from the given parse context.
+        /// </summary>
+        /// <remarks>
+        /// It is assumed that the input is initially positioned after the tag specified by the codec.
+        /// This method will continue reading entries from the input until the end is reached, or
+        /// a different tag is encountered.
+        /// </remarks>
+        /// <param name="ctx">Input to read from</param>
+        /// <param name="codec">Codec describing how the key/value pairs are encoded</param>
+        [SecuritySafeCritical]
+        public void AddEntriesFrom(ref ParseContext ctx, Codec codec)
+        {
+            do
+            {
+                KeyValuePair<TKey, TValue> entry = ParsingPrimitivesMessages.ReadMapEntry(ref ctx, codec);
+                this[entry.Key] = entry.Value;
+            } while (ParsingPrimitives.MaybeConsumeTag(ref ctx.buffer, ref ctx.state, codec.MapTag));
+        }
+
+        /// <summary>
+        /// Writes the contents of this map to the given coded output stream, using the specified codec
+        /// to encode each entry.
+        /// </summary>
+        /// <param name="output">The output stream to write to.</param>
+        /// <param name="codec">The codec to use for each entry.</param>
+        public void WriteTo(CodedOutputStream output, Codec codec)
+        {
+            WriteContext.Initialize(output, out WriteContext ctx);
+            try
+            {
+                WriteTo(ref ctx, codec);
+            }
+            finally
+            {
+                ctx.CopyStateTo(output);
+            }
+        }
+
+        /// <summary>
+        /// Writes the contents of this map to the given write context, using the specified codec
+        /// to encode each entry.
+        /// </summary>
+        /// <param name="ctx">The write context to write to.</param>
+        /// <param name="codec">The codec to use for each entry.</param>
+        [SecuritySafeCritical]
+        public void WriteTo(ref WriteContext ctx, Codec codec)
+        {
+            foreach (var entry in list)
+            {
+                ctx.WriteTag(codec.MapTag);
+
+                WritingPrimitives.WriteLength(ref ctx.buffer, ref ctx.state, CalculateEntrySize(codec, entry));
+                codec.KeyCodec.WriteTagAndValue(ref ctx, entry.Key);
+                codec.ValueCodec.WriteTagAndValue(ref ctx, entry.Value);
+            }
+        }
+
+        /// <summary>
+        /// Calculates the size of this map based on the given entry codec.
+        /// </summary>
+        /// <param name="codec">The codec to use to encode each entry.</param>
+        /// <returns></returns>
+        public int CalculateSize(Codec codec)
+        {
+            if (Count == 0)
+            {
+                return 0;
+            }
+            int size = 0;
+            foreach (var entry in list)
+            {
+                int entrySize = CalculateEntrySize(codec, entry);
+
+                size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
+                size += CodedOutputStream.ComputeLengthSize(entrySize) + entrySize;
+            }
+            return size;
+        }
+
+        private static int CalculateEntrySize(Codec codec, KeyValuePair<TKey, TValue> entry)
+        {
+            return codec.KeyCodec.CalculateSizeWithTag(entry.Key) + codec.ValueCodec.CalculateSizeWithTag(entry.Value);
+        }
+
+        /// <summary>
+        /// Returns a string representation of this repeated field, in the same
+        /// way as it would be represented by the default JSON formatter.
+        /// </summary>
+        public override string ToString()
+        {
+            var writer = new StringWriter();
+            JsonFormatter.Default.WriteDictionary(writer, this);
+            return writer.ToString();
+        }
+
+        #region IDictionary explicit interface implementation
+        void IDictionary.Add(object key, object value)
+        {
+            Add((TKey)key, (TValue)value);
+        }
+
+        bool IDictionary.Contains(object key)
+        {
+            if (!(key is TKey))
+            {
+                return false;
+            }
+            return ContainsKey((TKey)key);
+        }
+
+        IDictionaryEnumerator IDictionary.GetEnumerator()
+        {
+            return new DictionaryEnumerator(GetEnumerator());
+        }
+
+        void IDictionary.Remove(object key)
+        {
+            ProtoPreconditions.CheckNotNull(key, nameof(key));
+            if (!(key is TKey))
+            {
+                return;
+            }
+            Remove((TKey)key);
+        }
+
+        void ICollection.CopyTo(Array array, int index)
+        {
+            // This is ugly and slow as heck, but with any luck it will never be used anyway.
+            ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();
+            temp.CopyTo(array, index);
+        }
+
+        bool IDictionary.IsFixedSize { get { return false; } }
+
+        ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
+
+        ICollection IDictionary.Values { get { return (ICollection)Values; } }
+
+        bool ICollection.IsSynchronized { get { return false; } }
+
+        object ICollection.SyncRoot { get { return this; } }
+
+        object IDictionary.this[object key]
+        {
+            get
+            {
+                ProtoPreconditions.CheckNotNull(key, nameof(key));
+                if (!(key is TKey))
+                {
+                    return null;
+                }
+                TValue value;
+                TryGetValue((TKey)key, out value);
+                return value;
+            }
+
+            set
+            {
+                this[(TKey)key] = (TValue)value;
+            }
+        }
+        #endregion
+
+        #region IReadOnlyDictionary explicit interface implementation
+#if !NET35
+        IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
+
+        IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
+#endif
+        #endregion
+
+        private class DictionaryEnumerator : IDictionaryEnumerator
+        {
+            private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
+
+            internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
+            {
+                this.enumerator = enumerator;
+            }
+
+            public bool MoveNext()
+            {
+                return enumerator.MoveNext();
+            }
+
+            public void Reset()
+            {
+                enumerator.Reset();
+            }
+
+            public object Current { get { return Entry; } }
+            public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
+            public object Key { get { return enumerator.Current.Key; } }
+            public object Value { get { return enumerator.Current.Value; } }
+        }
+
+        /// <summary>
+        /// A codec for a specific map field. This contains all the information required to encode and
+        /// decode the nested messages.
+        /// </summary>
+        public sealed class Codec
+        {
+            private readonly FieldCodec<TKey> keyCodec;
+            private readonly FieldCodec<TValue> valueCodec;
+            private readonly uint mapTag;
+
+            /// <summary>
+            /// Creates a new entry codec based on a separate key codec and value codec,
+            /// and the tag to use for each map entry.
+            /// </summary>
+            /// <param name="keyCodec">The key codec.</param>
+            /// <param name="valueCodec">The value codec.</param>
+            /// <param name="mapTag">The map tag to use to introduce each map entry.</param>
+            public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCodec, uint mapTag)
+            {
+                this.keyCodec = keyCodec;
+                this.valueCodec = valueCodec;
+                this.mapTag = mapTag;
+            }
+
+            /// <summary>
+            /// The key codec.
+            /// </summary>
+            internal FieldCodec<TKey> KeyCodec => keyCodec;
+
+            /// <summary>
+            /// The value codec.
+            /// </summary>
+            internal FieldCodec<TValue> ValueCodec => valueCodec;
+
+            /// <summary>
+            /// The tag used in the enclosing message to indicate map entries.
+            /// </summary>
+            internal uint MapTag => mapTag;
+        }
+
+        private class MapView<T> : ICollection<T>, ICollection
+        {
+            private readonly MapField<TKey, TValue> parent;
+            private readonly Func<KeyValuePair<TKey, TValue>, T> projection;
+            private readonly Func<T, bool> containsCheck;
+
+            internal MapView(
+                MapField<TKey, TValue> parent,
+                Func<KeyValuePair<TKey, TValue>, T> projection,
+                Func<T, bool> containsCheck)
+            {
+                this.parent = parent;
+                this.projection = projection;
+                this.containsCheck = containsCheck;
+            }
+
+            public int Count { get { return parent.Count; } }
+
+            public bool IsReadOnly { get { return true; } }
+
+            public bool IsSynchronized { get { return false; } }
+
+            public object SyncRoot { get { return parent; } }
+
+            public void Add(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            public void Clear()
+            {
+                throw new NotSupportedException();
+            }
+
+            public bool Contains(T item)
+            {
+                return containsCheck(item);
+            }
+
+            public void CopyTo(T[] array, int arrayIndex)
+            {
+                if (arrayIndex < 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(arrayIndex));
+                }
+                if (arrayIndex + Count > array.Length)
+                {
+                    throw new ArgumentException("Not enough space in the array", nameof(array));
+                }
+                foreach (var item in this)
+                {
+                    array[arrayIndex++] = item;
+                }
+            }
+
+            public IEnumerator<T> GetEnumerator()
+            {
+                return parent.list.Select(projection).GetEnumerator();
+            }
+
+            public bool Remove(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                return GetEnumerator();
+            }
+
+            public void CopyTo(Array array, int index)
+            {
+                if (index < 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(index));
+                }
+                if (index + Count > array.Length)
+                {
+                    throw new ArgumentException("Not enough space in the array", nameof(array));
+                }
+                foreach (var item in this)
+                {
+                    array.SetValue(item, index++);
+                }
+            }
+        }
+    }
+}