1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 //----------------------------------------------------------------------- 4 // </copyright> 5 // <summary>A read-only dictionary wrapper which converts values as they are accessed.</summary> 6 //----------------------------------------------------------------------- 7 8 using System; 9 using System.Collections.Generic; 10 using System.Linq; 11 using System.Text; 12 13 using Microsoft.Build.Evaluation; 14 using Microsoft.Build.Shared; 15 16 namespace Microsoft.Build.Collections 17 { 18 /// <summary> 19 /// Implementation of a dictionary which acts as a read-only wrapper on another dictionary, but 20 /// converts values as they are accessed to another type. 21 /// </summary> 22 /// <typeparam name="K">The backing dictionary's key type.</typeparam> 23 /// <typeparam name="V">The backing dictionary's value type.</typeparam> 24 /// <typeparam name="N">The desired value type.</typeparam> 25 internal class ReadOnlyConvertingDictionary<K, V, N> : IDictionary<K, N> 26 { 27 /// <summary> 28 /// The backing dictionary. 29 /// </summary> 30 private readonly IDictionary<K, V> _backing; 31 32 /// <summary> 33 /// The delegate used to convert values. 34 /// </summary> 35 private readonly Func<V, N> _converter; 36 37 /// <summary> 38 /// Constructor. 39 /// </summary> ReadOnlyConvertingDictionary(IDictionary<K, V> backing, Func<V, N> converter)40 internal ReadOnlyConvertingDictionary(IDictionary<K, V> backing, Func<V, N> converter) 41 { 42 ErrorUtilities.VerifyThrowArgumentNull(backing, "backing"); 43 ErrorUtilities.VerifyThrowArgumentNull(converter, "converter"); 44 45 _backing = backing; 46 _converter = converter; 47 } 48 49 #region IDictionary<string,string> Members 50 51 /// <summary> 52 /// Returns the collection of keys in the dictionary. 53 /// </summary> 54 public ICollection<K> Keys 55 { 56 get { return _backing.Keys; } 57 } 58 59 /// <summary> 60 /// Returns the collection of values in the dictionary. 61 /// </summary> 62 public ICollection<N> Values 63 { 64 get 65 { 66 ErrorUtilities.ThrowInternalError("Values is not supported on ReadOnlyConvertingDictionary."); 67 68 // Show the compiler that this always throws: 69 throw new NotImplementedException(); 70 } 71 } 72 73 /// <summary> 74 /// Returns the number of items in the collection. 75 /// </summary> 76 public int Count 77 { 78 get { return _backing.Count; } 79 } 80 81 /// <summary> 82 /// Returns true if the collection is read-only. 83 /// </summary> 84 public bool IsReadOnly 85 { 86 get { return true; } 87 } 88 89 /// <summary> 90 /// Accesses the value for the specified key. 91 /// </summary> 92 public N this[K key] 93 { 94 get 95 { 96 return _converter(_backing[key]); 97 } 98 99 set 100 { 101 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 102 } 103 } 104 105 /// <summary> 106 /// Adds a value to the dictionary. 107 /// </summary> Add(K key, N value)108 public void Add(K key, N value) 109 { 110 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 111 } 112 113 /// <summary> 114 /// Returns true if the dictionary contains the specified key. 115 /// </summary> ContainsKey(K key)116 public bool ContainsKey(K key) 117 { 118 return _backing.ContainsKey(key); 119 } 120 121 /// <summary> 122 /// Removes the entry for the specified key from the dictionary. 123 /// </summary> Remove(K key)124 public bool Remove(K key) 125 { 126 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 127 return false; 128 } 129 130 /// <summary> 131 /// Attempts to find the value for the specified key in the dictionary. 132 /// </summary> TryGetValue(K key, out N value)133 public bool TryGetValue(K key, out N value) 134 { 135 V originalValue; 136 if (_backing.TryGetValue(key, out originalValue)) 137 { 138 value = _converter(originalValue); 139 return true; 140 } 141 142 value = default(N); 143 return false; 144 } 145 146 #endregion 147 148 #region ICollection<KeyValuePair<string,string>> Members 149 150 /// <summary> 151 /// Adds an item to the collection. 152 /// </summary> Add(KeyValuePair<K, N> item)153 public void Add(KeyValuePair<K, N> item) 154 { 155 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 156 } 157 158 /// <summary> 159 /// Clears the collection. 160 /// </summary> Clear()161 public void Clear() 162 { 163 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 164 } 165 166 /// <summary> 167 /// Returns true ff the collection contains the specified item. 168 /// </summary> Contains(KeyValuePair<K, N> item)169 public bool Contains(KeyValuePair<K, N> item) 170 { 171 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedConvertingCollectionValueToBacking"); 172 return false; 173 } 174 175 /// <summary> 176 /// Copies all of the elements of the collection to the specified array. 177 /// </summary> CopyTo(KeyValuePair<K, N>[] array, int arrayIndex)178 public void CopyTo(KeyValuePair<K, N>[] array, int arrayIndex) 179 { 180 ErrorUtilities.VerifyThrow(array.Length - arrayIndex >= _backing.Count, "Specified array size insufficient to hold the contents of the collection."); 181 182 foreach (KeyValuePair<K, V> pair in _backing) 183 { 184 array[arrayIndex++] = KeyValueConverter(pair); 185 } 186 } 187 188 /// <summary> 189 /// Remove an item from the dictionary. 190 /// </summary> Remove(KeyValuePair<K, N> item)191 public bool Remove(KeyValuePair<K, N> item) 192 { 193 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 194 return false; 195 } 196 197 #endregion 198 199 #region IEnumerable<KeyValuePair<K, N>> Members 200 201 /// <summary> 202 /// Implementation of generic IEnumerable.GetEnumerator() 203 /// </summary> GetEnumerator()204 public IEnumerator<KeyValuePair<K, N>> GetEnumerator() 205 { 206 return new ConvertingEnumerable<KeyValuePair<K, V>, KeyValuePair<K, N>>(_backing, KeyValueConverter).GetEnumerator(); 207 } 208 209 #endregion 210 211 #region IEnumerable Members 212 213 /// <summary> 214 /// Implementation of IEnumerable.GetEnumerator() 215 /// </summary> System.Collections.IEnumerable.GetEnumerator()216 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 217 { 218 return ((IEnumerable<KeyValuePair<K, N>>)this).GetEnumerator(); 219 } 220 221 #endregion 222 223 /// <summary> 224 /// Delegate used by ConvertingEnumerable 225 /// </summary> KeyValueConverter(KeyValuePair<K, V> original)226 private KeyValuePair<K, N> KeyValueConverter(KeyValuePair<K, V> original) 227 { 228 return new KeyValuePair<K, N>(original.Key, _converter(original.Value)); 229 } 230 } 231 } 232