// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // using System; using System.Security; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; namespace System.Runtime.InteropServices.WindowsRuntime { // This is a set of stub methods implementing the support for the IDictionary`2 interface on WinRT // objects that support IMap`2. Used by the interop mashaling infrastructure. // // The methods on this class must be written VERY carefully to avoid introducing security holes. // That's because they are invoked with special "this"! The "this" object // for all of these methods are not MapToDictionaryAdapter objects. Rather, they are of type // IMap. No actual MapToDictionaryAdapter object is ever instantiated. Thus, you will see // a lot of expressions that cast "this" to "IMap". internal sealed class MapToDictionaryAdapter { private MapToDictionaryAdapter() { Debug.Assert(false, "This class is never instantiated"); } // V this[K key] { get } internal V Indexer_Get(K key) { if (key == null) throw new ArgumentNullException(nameof(key)); Contract.EndContractBlock(); IMap _this = JitHelpers.UnsafeCast>(this); return Lookup(_this, key); } // V this[K key] { set } internal void Indexer_Set(K key, V value) { if (key == null) throw new ArgumentNullException(nameof(key)); Contract.EndContractBlock(); IMap _this = JitHelpers.UnsafeCast>(this); Insert(_this, key, value); } // ICollection Keys { get } internal ICollection Keys() { IMap _this = JitHelpers.UnsafeCast>(this); IDictionary dictionary = (IDictionary)_this; return new DictionaryKeyCollection(dictionary); } // ICollection Values { get } internal ICollection Values() { IMap _this = JitHelpers.UnsafeCast>(this); IDictionary dictionary = (IDictionary)_this; return new DictionaryValueCollection(dictionary); } // bool ContainsKey(K key) [Pure] internal bool ContainsKey(K key) { if (key == null) throw new ArgumentNullException(nameof(key)); IMap _this = JitHelpers.UnsafeCast>(this); return _this.HasKey(key); } // void Add(K key, V value) internal void Add(K key, V value) { if (key == null) throw new ArgumentNullException(nameof(key)); if (ContainsKey(key)) throw new ArgumentException(Environment.GetResourceString("Argument_AddingDuplicate")); Contract.EndContractBlock(); IMap _this = JitHelpers.UnsafeCast>(this); Insert(_this, key, value); } // bool Remove(TKey key) internal bool Remove(K key) { if (key == null) throw new ArgumentNullException(nameof(key)); IMap _this = JitHelpers.UnsafeCast>(this); if (!_this.HasKey(key)) return false; try { _this.Remove(key); return true; } catch (Exception ex) { if (__HResults.E_BOUNDS == ex._HResult) return false; throw; } } // bool TryGetValue(TKey key, out TValue value) internal bool TryGetValue(K key, out V value) { if (key == null) throw new ArgumentNullException(nameof(key)); IMap _this = JitHelpers.UnsafeCast>(this); if (!_this.HasKey(key)) { value = default(V); return false; } try { value = Lookup(_this, key); return true; } catch (KeyNotFoundException) { value = default(V); return false; } } // Helpers: private static V Lookup(IMap _this, K key) { Contract.Requires(null != key); try { return _this.Lookup(key); } catch (Exception ex) { if (__HResults.E_BOUNDS == ex._HResult) throw new KeyNotFoundException(Environment.GetResourceString("Arg_KeyNotFound")); throw; } } private static bool Insert(IMap _this, K key, V value) { Contract.Requires(null != key); bool replaced = _this.Insert(key, value); return replaced; } } }