File: system\runtime\interopservices\windowsruntime\imapviewtoireadonlydictionaryadapter.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
//
// <OWNER>GPaperin</OWNER>
// <OWNER>Microsoft</OWNER>
 
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 IReadOnlyDictionary`2 interface on WinRT
    // objects that support IMapView`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 IMapViewToIReadOnlyDictionaryAdapter objects. Rather, they are of type
    // IMapView<K, V>. No actual IMapViewToIReadOnlyDictionaryAdapter object is ever instantiated. Thus, you will see
    // a lot of expressions that cast "this" to "IMapView<K, V>".
    [DebuggerDisplay("Count = {Count}")]
    internal sealed class IMapViewToIReadOnlyDictionaryAdapter
    {
        private IMapViewToIReadOnlyDictionaryAdapter()
        {
            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();
 
            IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this);
            return Lookup(_this, key);
        }
 
        // IEnumerable<K> Keys { get }
        [SecurityCritical]
        internal IEnumerable<K> Keys<K, V>()
        {
            IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this);
            IReadOnlyDictionary<K, V> roDictionary = (IReadOnlyDictionary<K, V>)_this;
            return new ReadOnlyDictionaryKeyCollection<K, V>(roDictionary);
        }
 
        // IEnumerable<V> Values { get }
        [SecurityCritical]
        internal IEnumerable<V> Values<K, V>()
        {
            IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this);
            IReadOnlyDictionary<K, V> roDictionary = (IReadOnlyDictionary<K, V>)_this;
            return new ReadOnlyDictionaryValueCollection<K, V>(roDictionary);
        }
 
        // bool ContainsKey(K key)
        [Pure]
        [SecurityCritical]
        internal bool ContainsKey<K, V>(K key)
        {
            if (key == null)
                throw new ArgumentNullException("key");
 
            IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this);
            return _this.HasKey(key);
        }
 
        // 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");
 
            IMapView<K, V> _this = JitHelpers.UnsafeCast<IMapView<K, V>>(this);
 
            // It may be faster to call HasKey then Lookup.  On failure, we would otherwise
            // throw an exception from Lookup.
            if (!_this.HasKey(key))
            {
                value = default(V);
                return false;
            }
 
            try
            {
                value = _this.Lookup(key);
                return true;
            }
            catch (Exception ex)  // Still may hit this case due to a ----, or a potential bug.
            {
                if (__HResults.E_BOUNDS == ex._HResult)
                {
                    value = default(V);
                    return false;
                }
                throw;
            }
        }
 
        #region Helpers
 
        private static V Lookup<K, V>(IMapView<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;
            }
        }
 
        #endregion Helpers
    }
 
    // Note: One day we may make these return IReadOnlyCollection<T>
    [Serializable]
    [DebuggerDisplay("Count = {Count}")]
    internal sealed class ReadOnlyDictionaryKeyCollection<TKey, TValue> : IEnumerable<TKey>
    {
        private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
 
        public ReadOnlyDictionaryKeyCollection(IReadOnlyDictionary<TKey, TValue> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
 
            this.dictionary = dictionary;
        }
 
        /*
        public void CopyTo(TKey[] array, int index)
        {
            if (array == null)
                throw new ArgumentNullException("array");
            if (index < 0)
                throw new ArgumentOutOfRangeException("index");
            if (array.Length <= index && this.Count > 0)
                throw new ArgumentException(Environment.GetResourceString("Arg_IndexOutOfRangeException"));
            if (array.Length - index < dictionary.Count)
                throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection"));
 
            int i = index;
            foreach (KeyValuePair<TKey, TValue> mapping in dictionary)
            {
                array[i++] = mapping.Key;
            }
        }
        
        public int Count {
            get { return dictionary.Count; }
        }
 
        public bool Contains(TKey item)
        {
            return dictionary.ContainsKey(item);
        }
        */
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<TKey>)this).GetEnumerator();
        }
 
        public IEnumerator<TKey> GetEnumerator()
        {
            return new ReadOnlyDictionaryKeyEnumerator<TKey, TValue>(dictionary);
        }
    }  // public class ReadOnlyDictionaryKeyCollection<TKey, TValue>
 
 
    [Serializable]
    internal sealed class ReadOnlyDictionaryKeyEnumerator<TKey, TValue> : IEnumerator<TKey>
    {
        private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
        private IEnumerator<KeyValuePair<TKey, TValue>> enumeration;
 
        public ReadOnlyDictionaryKeyEnumerator(IReadOnlyDictionary<TKey, TValue> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
 
            this.dictionary = dictionary;
            this.enumeration = dictionary.GetEnumerator();
        }
 
        void IDisposable.Dispose()
        {
            enumeration.Dispose();
        }
 
        public bool MoveNext()
        {
            return enumeration.MoveNext();
        }
 
        Object IEnumerator.Current {
            get { return ((IEnumerator<TKey>)this).Current; }
        }
 
        public TKey Current {
            get { return enumeration.Current.Key; }
        }
 
        public void Reset()
        {
            enumeration = dictionary.GetEnumerator();
        }
    }  // class ReadOnlyDictionaryKeyEnumerator<TKey, TValue>
 
 
    [Serializable]
    [DebuggerDisplay("Count = {Count}")]
    internal sealed class ReadOnlyDictionaryValueCollection<TKey, TValue> : IEnumerable<TValue>
    {
        private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
 
        public ReadOnlyDictionaryValueCollection(IReadOnlyDictionary<TKey, TValue> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
 
            this.dictionary = dictionary;
        }
 
        /*
        public void CopyTo(TValue[] array, int index)
        {
            if (array == null)
                throw new ArgumentNullException("array");
            if (index < 0)
                throw new ArgumentOutOfRangeException("index");
            if (array.Length <= index && this.Count > 0)
                throw new ArgumentException(Environment.GetResourceString("Arg_IndexOutOfRangeException"));
            if (array.Length - index < dictionary.Count)
                throw new ArgumentException(Environment.GetResourceString("Argument_InsufficientSpaceToCopyCollection"));
 
            int i = index;
            foreach (KeyValuePair<TKey, TValue> mapping in dictionary)
            {
                array[i++] = mapping.Value;
            }
        }
 
        public int Count {
            get { return dictionary.Count; }
        }
 
        public bool Contains(TValue item)
        {
            EqualityComparer<TValue> comparer = EqualityComparer<TValue>.Default;
            foreach (TValue value in this)
                if (comparer.Equals(item, value))
                    return true;
            return false;
        }
        */
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<TValue>)this).GetEnumerator();
        }
 
        public IEnumerator<TValue> GetEnumerator()
        {
            return new ReadOnlyDictionaryValueEnumerator<TKey, TValue>(dictionary);
        }
    }  // public class ReadOnlyDictionaryValueCollection<TKey, TValue>
 
 
    [Serializable]
    internal sealed class ReadOnlyDictionaryValueEnumerator<TKey, TValue> : IEnumerator<TValue>
    {
        private readonly IReadOnlyDictionary<TKey, TValue> dictionary;
        private IEnumerator<KeyValuePair<TKey, TValue>> enumeration;
 
        public ReadOnlyDictionaryValueEnumerator(IReadOnlyDictionary<TKey, TValue> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
 
            this.dictionary = dictionary;
            this.enumeration = dictionary.GetEnumerator();
        }
 
        void IDisposable.Dispose()
        {
            enumeration.Dispose();
        }
 
        public bool MoveNext()
        {
            return enumeration.MoveNext();
        }
 
        Object IEnumerator.Current {
            get { return ((IEnumerator<TValue>)this).Current; }
        }
 
        public TValue Current {
            get { return enumeration.Current.Value; }
        }
 
        public void Reset()
        {
            enumeration = dictionary.GetEnumerator();
        }
    }  // class ReadOnlyDictionaryValueEnumerator<TKey, TValue>
 
}