// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Routing { /// /// An type for route values. /// public class RouteValueDictionary : IDictionary, IReadOnlyDictionary { /// /// An empty, cached instance of . /// internal static readonly IReadOnlyDictionary Empty = new RouteValueDictionary(); private readonly Dictionary _dictionary; /// /// Creates an empty . /// public RouteValueDictionary() { _dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); } /// /// Creates a initialized with the specified . /// /// An object to initialize the dictionary. The value can be of type /// or /// or an object with public properties as key-value pairs. /// /// /// If the value is a dictionary or other , /// then its entries are copied. Otherwise the object is interpreted as a set of key-value pairs where the /// property names are keys, and property values are the values, and copied into the dictionary. /// Only public instance non-index properties are considered. /// public RouteValueDictionary(object values) : this() { if (values != null) { var keyValuePairCollection = values as IEnumerable>; if (keyValuePairCollection != null) { foreach (var kvp in keyValuePairCollection) { Add(kvp.Key, kvp.Value); } return; } var type = values.GetType(); var allProperties = type.GetRuntimeProperties(); // This is done to support 'new' properties that hide a property on a base class var orderedByDeclaringType = allProperties.OrderBy(p => p.DeclaringType == type ? 0 : 1); foreach (var property in orderedByDeclaringType) { if (property.GetMethod != null && property.GetMethod.IsPublic && !property.GetMethod.IsStatic && property.GetIndexParameters().Length == 0) { var value = property.GetValue(values); if (ContainsKey(property.Name) && property.DeclaringType != type) { // This is a hidden property, ignore it. } else { Add(property.Name, value); } } } } } /// public object this[[NotNull] string key] { get { object value; _dictionary.TryGetValue(key, out value); return value; } set { _dictionary[key] = value; } } /// /// Gets the comparer for this dictionary. /// /// /// This will always be a reference to /// public IEqualityComparer Comparer { get { return _dictionary.Comparer; } } /// public int Count { get { return _dictionary.Count; } } /// bool ICollection>.IsReadOnly { get { return ((ICollection>)_dictionary).IsReadOnly; } } /// public Dictionary.KeyCollection Keys { get { return _dictionary.Keys; } } /// ICollection IDictionary.Keys { get { return _dictionary.Keys; } } IEnumerable IReadOnlyDictionary.Keys { get { return _dictionary.Keys; } } /// public Dictionary.ValueCollection Values { get { return _dictionary.Values; } } /// ICollection IDictionary.Values { get { return _dictionary.Values; } } IEnumerable IReadOnlyDictionary.Values { get { return _dictionary.Values; } } /// void ICollection>.Add(KeyValuePair item) { ((ICollection>)_dictionary).Add(item); } /// public void Add([NotNull] string key, object value) { _dictionary.Add(key, value); } /// public void Clear() { _dictionary.Clear(); } /// bool ICollection>.Contains(KeyValuePair item) { return ((ICollection>)_dictionary).Contains(item); } /// public bool ContainsKey([NotNull] string key) { return _dictionary.ContainsKey(key); } /// void ICollection>.CopyTo( [NotNull] KeyValuePair[] array, int arrayIndex) { ((ICollection>)_dictionary).CopyTo(array, arrayIndex); } /// public Dictionary.Enumerator GetEnumerator() { return _dictionary.GetEnumerator(); } /// IEnumerator> IEnumerable>.GetEnumerator() { return _dictionary.GetEnumerator(); } /// IEnumerator IEnumerable.GetEnumerator() { return _dictionary.GetEnumerator(); } /// bool ICollection>.Remove(KeyValuePair item) { return ((ICollection>)_dictionary).Remove(item); } /// public bool Remove([NotNull] string key) { return _dictionary.Remove(key); } /// public bool TryGetValue([NotNull] string key, out object value) { return _dictionary.TryGetValue(key, out value); } } }