diff options
Diffstat (limited to 'src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs')
-rw-r--r-- | src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs new file mode 100644 index 0000000000..d7897ced9f --- /dev/null +++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs @@ -0,0 +1,183 @@ +// 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.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<K, V>. No actual MapToDictionaryAdapter object is ever instantiated. Thus, you will see + // a lot of expressions that cast "this" to "IMap<K, V>". + internal sealed class MapToDictionaryAdapter + { + private MapToDictionaryAdapter() + { + Contract.Assert(false, "This class is never instantiated"); + } + + // V this[K key] { get } + [SecurityCritical] + internal V Indexer_Get<K, V>(K key) + { + if (key == null) + throw new ArgumentNullException("key"); + + Contract.EndContractBlock(); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + return Lookup(_this, key); + } + + // V this[K key] { set } + [SecurityCritical] + internal void Indexer_Set<K, V>(K key, V value) + { + if (key == null) + throw new ArgumentNullException("key"); + + Contract.EndContractBlock(); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + Insert(_this, key, value); + } + + // ICollection<K> Keys { get } + [SecurityCritical] + internal ICollection<K> Keys<K, V>() + { + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + IDictionary<K, V> dictionary = (IDictionary<K, V>)_this; + return new DictionaryKeyCollection<K, V>(dictionary); + } + + // ICollection<V> Values { get } + [SecurityCritical] + internal ICollection<V> Values<K, V>() + { + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + IDictionary<K, V> dictionary = (IDictionary<K, V>)_this; + return new DictionaryValueCollection<K, V>(dictionary); + } + + // bool ContainsKey(K key) + [Pure] + [SecurityCritical] + internal bool ContainsKey<K, V>(K key) + { + if (key == null) + throw new ArgumentNullException("key"); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + return _this.HasKey(key); + } + + // void Add(K key, V value) + [SecurityCritical] + internal void Add<K, V>(K key, V value) + { + if (key == null) + throw new ArgumentNullException("key"); + + if (ContainsKey<K, V>(key)) + throw new ArgumentException(Environment.GetResourceString("Argument_AddingDuplicate")); + + Contract.EndContractBlock(); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(this); + Insert(_this, key, value); + } + + // bool Remove(TKey key) + [SecurityCritical] + internal bool Remove<K, V>(K key) + { + if (key == null) + throw new ArgumentNullException("key"); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(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) + [SecurityCritical] + internal bool TryGetValue<K, V>(K key, out V value) + { + if (key == null) + throw new ArgumentNullException("key"); + + IMap<K, V> _this = JitHelpers.UnsafeCast<IMap<K, V>>(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<K, V>(IMap<K, V> _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<K, V>(IMap<K, V> _this, K key, V value) + { + Contract.Requires(null != key); + + bool replaced = _this.Insert(key, value); + return replaced; + } + } +} |