using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
namespace Mustache
{
///
/// Provides methods for creating instances of PropertyDictionary.
///
internal sealed class PropertyDictionary : IDictionary
{
private static readonly Dictionary>> _cache = new Dictionary>>();
private readonly object _instance;
private readonly Dictionary> _typeCache;
///
/// Initializes a new instance of a PropertyDictionary.
///
/// The instance to wrap in the PropertyDictionary.
public PropertyDictionary(object instance)
{
_instance = instance;
if (instance == null)
{
_typeCache = new Dictionary>();
}
else
{
_typeCache = getCacheType(_instance);
}
}
private static Dictionary> getCacheType(object instance)
{
Type type = instance.GetType();
Dictionary> typeCache;
if (!_cache.TryGetValue(type, out typeCache))
{
typeCache = new Dictionary>();
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy;
foreach (PropertyInfo propertyInfo in type.GetProperties(flags))
{
if (!propertyInfo.IsSpecialName)
{
typeCache.Add(propertyInfo.Name, i => propertyInfo.GetValue(i, null));
}
}
foreach (FieldInfo fieldInfo in type.GetFields(flags))
{
typeCache.Add(fieldInfo.Name, i => fieldInfo.GetValue(i));
}
_cache.Add(type, typeCache);
}
return typeCache;
}
///
/// Gets the underlying instance.
///
public object Instance
{
get { return _instance; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
void IDictionary.Add(string key, object value)
{
throw new NotSupportedException();
}
///
/// Determines whether a property with the given name exists.
///
/// The name of the property.
/// True if the property exists; otherwise, false.
public bool ContainsKey(string key)
{
return _typeCache.ContainsKey(key);
}
///
/// Gets the name of the properties in the type.
///
public ICollection Keys
{
get { return _typeCache.Keys; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
bool IDictionary.Remove(string key)
{
throw new NotSupportedException();
}
///
/// Tries to get the value for the given property name.
///
/// The name of the property to get the value for.
/// The variable to store the value of the property or the default value if the property is not found.
/// True if a property with the given name is found; otherwise, false.
/// The name of the property was null.
public bool TryGetValue(string key, out object value)
{
Func