// 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