From 3f45d7c11e200184cfc09fb92efe25a63df1eef1 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Sat, 8 Aug 2015 07:17:58 +0100 Subject: Implement Keys and Values as views --- csharp/src/Google.Protobuf/Collections/MapField.cs | 88 +++++++++++++++++++++- 1 file changed, 84 insertions(+), 4 deletions(-) (limited to 'csharp/src/Google.Protobuf/Collections/MapField.cs') diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs index dc4b04cb..6dcdc100 100644 --- a/csharp/src/Google.Protobuf/Collections/MapField.cs +++ b/csharp/src/Google.Protobuf/Collections/MapField.cs @@ -136,6 +136,12 @@ namespace Google.Protobuf.Collections return map.ContainsKey(key); } + private bool ContainsValue(TValue value) + { + var comparer = EqualityComparer.Default; + return list.Any(pair => comparer.Equals(pair.Value, value)); + } + /// /// Removes the entry identified by the given key from the map. /// @@ -221,17 +227,15 @@ namespace Google.Protobuf.Collections } } - // TODO: Make these views? - /// /// Gets a collection containing the keys in the map. /// - public ICollection Keys { get { return list.Select(t => t.Key).ToList(); } } + public ICollection Keys { get { return new MapView(this, pair => pair.Key, ContainsKey); } } /// /// Gets a collection containing the values in the map. /// - public ICollection Values { get { return list.Select(t => t.Value).ToList(); } } + public ICollection Values { get { return new MapView(this, pair => pair.Value, ContainsValue); } } /// /// Adds the specified entries to the map. @@ -658,5 +662,81 @@ namespace Google.Protobuf.Collections MessageDescriptor IMessage.Descriptor { get { return null; } } } } + + private class MapView : ICollection, ICollection + { + private readonly MapField parent; + private readonly Func, T> projection; + private readonly Func containsCheck; + + internal MapView( + MapField parent, + Func, T> projection, + Func 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("arrayIndex"); + } + if (arrayIndex + Count >= array.Length) + { + throw new ArgumentException("Not enough space in the array", "array"); + } + foreach (var item in this) + { + array[arrayIndex++] = item; + } + } + + public IEnumerator 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) + { + throw new NotImplementedException(); + } + } } } -- cgit v1.2.3