1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
9 using System.Collections;
10 using System.Collections.Generic;
11 using System.Diagnostics;
12 using System.Runtime.InteropServices;
13 using System.Runtime.CompilerServices;
14 using Internal.Runtime.CompilerServices;
16 namespace System.Runtime.InteropServices.WindowsRuntime
18 // This is a set of stub methods implementing the support for the IReadOnlyDictionary`2 interface on WinRT
19 // objects that support IMapView`2. Used by the interop mashaling infrastructure.
21 // The methods on this class must be written VERY carefully to avoid introducing security holes.
22 // That's because they are invoked with special "this"! The "this" object
23 // for all of these methods are not IMapViewToIReadOnlyDictionaryAdapter objects. Rather, they are of type
24 // IMapView<K, V>. No actual IMapViewToIReadOnlyDictionaryAdapter object is ever instantiated. Thus, you will see
25 // a lot of expressions that cast "this" to "IMapView<K, V>".
26 [DebuggerDisplay("Count = {Count}")]
27 internal sealed class IMapViewToIReadOnlyDictionaryAdapter
29 private IMapViewToIReadOnlyDictionaryAdapter()
31 Debug.Fail("This class is never instantiated");
34 // V this[K key] { get }
35 internal V Indexer_Get<K, V>(K key)
38 throw new ArgumentNullException(nameof(key));
40 IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
41 return Lookup(_this, key);
44 // IEnumerable<K> Keys { get }
45 internal IEnumerable<K> Keys<K, V>()
47 IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
48 IReadOnlyDictionary<K, V> roDictionary = (IReadOnlyDictionary<K, V>)_this;
49 return new ReadOnlyDictionaryKeyCollection<K, V>(roDictionary);
52 // IEnumerable<V> Values { get }
53 internal IEnumerable<V> Values<K, V>()
55 IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
56 IReadOnlyDictionary<K, V> roDictionary = (IReadOnlyDictionary<K, V>)_this;
57 return new ReadOnlyDictionaryValueCollection<K, V>(roDictionary);
60 // bool ContainsKey(K key)
61 internal bool ContainsKey<K, V>(K key)
64 throw new ArgumentNullException(nameof(key));
66 IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
67 return _this.HasKey(key);
70 // bool TryGetValue(TKey key, out TValue value)
71 internal bool TryGetValue<K, V>(K key, out V value)
74 throw new ArgumentNullException(nameof(key));
76 IMapView<K, V> _this = Unsafe.As<IMapView<K, V>>(this);
78 // It may be faster to call HasKey then Lookup. On failure, we would otherwise
79 // throw an exception from Lookup.
80 if (!_this.HasKey(key))
88 value = _this.Lookup(key);
91 catch (Exception ex) // Still may hit this case due to a race condition
93 if (HResults.E_BOUNDS == ex.HResult)
104 private static V Lookup<K, V>(IMapView<K, V> _this, K key)
106 Debug.Assert(null != key);
110 return _this.Lookup(key);
114 if (HResults.E_BOUNDS == ex.HResult)
115 throw new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString()));
123 // Note: One day we may make these return IReadOnlyCollection<T>
124 [DebuggerDisplay("Count = {Count}")]
125 internal sealed class ReadOnlyDictionaryKeyCollection<TKey, TValue> : IEnumerable<TKey>
127 private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
129 public ReadOnlyDictionaryKeyCollection(IReadOnlyDictionary<TKey, TValue> dictionary)
131 if (dictionary == null)
132 throw new ArgumentNullException(nameof(dictionary));
134 this.dictionary = dictionary;
138 public void CopyTo(TKey[] array, int index)
141 throw new ArgumentNullException(nameof(array));
143 throw new ArgumentOutOfRangeException(nameof(index));
144 if (array.Length <= index && this.Count > 0)
145 throw new ArgumentException(SR.Arg_IndexOutOfRangeException);
146 if (array.Length - index < dictionary.Count)
147 throw new ArgumentException(SR.Argument_InsufficientSpaceToCopyCollection);
150 foreach (KeyValuePair<TKey, TValue> mapping in dictionary)
152 array[i++] = mapping.Key;
157 get { return dictionary.Count; }
160 public bool Contains(TKey item)
162 return dictionary.ContainsKey(item);
166 IEnumerator IEnumerable.GetEnumerator()
168 return ((IEnumerable<TKey>)this).GetEnumerator();
171 public IEnumerator<TKey> GetEnumerator()
173 return new ReadOnlyDictionaryKeyEnumerator<TKey, TValue>(dictionary);
175 } // public class ReadOnlyDictionaryKeyCollection<TKey, TValue>
178 internal sealed class ReadOnlyDictionaryKeyEnumerator<TKey, TValue> : IEnumerator<TKey>
180 private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
181 private IEnumerator<KeyValuePair<TKey, TValue>> enumeration;
183 public ReadOnlyDictionaryKeyEnumerator(IReadOnlyDictionary<TKey, TValue> dictionary)
185 if (dictionary == null)
186 throw new ArgumentNullException(nameof(dictionary));
188 this.dictionary = dictionary;
189 enumeration = dictionary.GetEnumerator();
192 void IDisposable.Dispose()
194 enumeration.Dispose();
197 public bool MoveNext()
199 return enumeration.MoveNext();
202 object IEnumerator.Current
204 get { return ((IEnumerator<TKey>)this).Current; }
209 get { return enumeration.Current.Key; }
214 enumeration = dictionary.GetEnumerator();
216 } // class ReadOnlyDictionaryKeyEnumerator<TKey, TValue>
219 [DebuggerDisplay("Count = {Count}")]
220 internal sealed class ReadOnlyDictionaryValueCollection<TKey, TValue> : IEnumerable<TValue>
222 private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
224 public ReadOnlyDictionaryValueCollection(IReadOnlyDictionary<TKey, TValue> dictionary)
226 if (dictionary == null)
227 throw new ArgumentNullException(nameof(dictionary));
229 this.dictionary = dictionary;
233 public void CopyTo(TValue[] array, int index)
236 throw new ArgumentNullException(nameof(array));
238 throw new ArgumentOutOfRangeException(nameof(index));
239 if (array.Length <= index && this.Count > 0)
240 throw new ArgumentException(SR.Arg_IndexOutOfRangeException);
241 if (array.Length - index < dictionary.Count)
242 throw new ArgumentException(SR.Argument_InsufficientSpaceToCopyCollection);
245 foreach (KeyValuePair<TKey, TValue> mapping in dictionary)
247 array[i++] = mapping.Value;
252 get { return dictionary.Count; }
255 public bool Contains(TValue item)
257 EqualityComparer<TValue> comparer = EqualityComparer<TValue>.Default;
258 foreach (TValue value in this)
259 if (comparer.Equals(item, value))
265 IEnumerator IEnumerable.GetEnumerator()
267 return ((IEnumerable<TValue>)this).GetEnumerator();
270 public IEnumerator<TValue> GetEnumerator()
272 return new ReadOnlyDictionaryValueEnumerator<TKey, TValue>(dictionary);
274 } // public class ReadOnlyDictionaryValueCollection<TKey, TValue>
277 internal sealed class ReadOnlyDictionaryValueEnumerator<TKey, TValue> : IEnumerator<TValue>
279 private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
280 private IEnumerator<KeyValuePair<TKey, TValue>> enumeration;
282 public ReadOnlyDictionaryValueEnumerator(IReadOnlyDictionary<TKey, TValue> dictionary)
284 if (dictionary == null)
285 throw new ArgumentNullException(nameof(dictionary));
287 this.dictionary = dictionary;
288 enumeration = dictionary.GetEnumerator();
291 void IDisposable.Dispose()
293 enumeration.Dispose();
296 public bool MoveNext()
298 return enumeration.MoveNext();
301 object IEnumerator.Current
303 get { return ((IEnumerator<TValue>)this).Current; }
306 public TValue Current
308 get { return enumeration.Current.Value; }
313 enumeration = dictionary.GetEnumerator();
315 } // class ReadOnlyDictionaryValueEnumerator<TKey, TValue>