Even more powerful dictionary detection

There were some more cases where an IDictionary<string, T> was not being
detected by the UpcastDictionary.
This commit is contained in:
Travis Parks 2014-06-25 11:04:51 -04:00
parent 80824c4e4b
commit 55ff1ef5de
3 changed files with 60 additions and 7 deletions

View File

@ -202,5 +202,22 @@ namespace Mustache.Test
}; };
CollectionAssert.AreEqual(expected, values, "The enumerator did not return the correct pairs."); CollectionAssert.AreEqual(expected, values, "The enumerator did not return the correct pairs.");
} }
/// <summary>
/// Newtonsoft's JSON.NET has an object called JObject. This is a concrete class
/// that inherits from IDictionary&lt;string, JToken&gt;. The UpcastDictionary
/// should be able to handle this type.
/// </summary>
[TestMethod]
public void ShouldHandleConcreteClassInheritingFromDictionary()
{
var dictionary = new ConcreteDictionary() { { "Name", "Bob" } };
var result = UpcastDictionary.Create(dictionary);
Assert.AreEqual(dictionary["Name"], result["Name"]);
}
public class ConcreteDictionary : Dictionary<string, string>
{
}
} }
} }

View File

@ -14,6 +14,6 @@ using System.Runtime.InteropServices;
[assembly: CLSCompliant(true)] [assembly: CLSCompliant(true)]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: Guid("e5a4263d-d450-4d85-a4d5-44c0a2822668")] [assembly: Guid("e5a4263d-d450-4d85-a4d5-44c0a2822668")]
[assembly: AssemblyVersion("0.2.5.0")] [assembly: AssemblyVersion("0.2.6.0")]
[assembly: AssemblyFileVersion("0.2.5.0")] [assembly: AssemblyFileVersion("0.2.6.0")]
[assembly: InternalsVisibleTo("mustache-sharp.test")] [assembly: InternalsVisibleTo("mustache-sharp.test")]

View File

@ -20,11 +20,48 @@ namespace Mustache
return sourceDictionary; return sourceDictionary;
} }
Type sourceType = source.GetType(); Type sourceType = source.GetType();
if (!sourceType.IsGenericType) var types = getTypes(sourceType);
return getDictionary(types, source);
}
private static IEnumerable<Type> getTypes(Type type)
{
HashSet<Type> types = new HashSet<Type>();
getTypes(types, type);
return types;
}
private static void getTypes(HashSet<Type> types, Type type)
{
if (type == null)
{
return;
}
types.Add(type);
getTypes(types, type.BaseType);
foreach (Type interfaceType in type.GetInterfaces())
{
getTypes(types, interfaceType);
}
}
private static IDictionary<string, object> getDictionary(IEnumerable<Type> types, object source)
{
var dictionaries = from type in types
let valueType = getValueType(type)
where valueType != null
let upcastType = typeof(UpcastDictionary<>).MakeGenericType(valueType)
select (IDictionary<string, object>)Activator.CreateInstance(upcastType, source);
return dictionaries.FirstOrDefault();
}
private static Type getValueType(Type type)
{
if (!type.IsGenericType)
{ {
return null; return null;
} }
Type[] argumentTypes = sourceType.GetGenericArguments(); Type[] argumentTypes = type.GetGenericArguments();
if (argumentTypes.Length != 2) if (argumentTypes.Length != 2)
{ {
return null; return null;
@ -36,12 +73,11 @@ namespace Mustache
} }
Type valueType = argumentTypes[1]; Type valueType = argumentTypes[1];
Type genericType = typeof(IDictionary<,>).MakeGenericType(typeof(string), valueType); Type genericType = typeof(IDictionary<,>).MakeGenericType(typeof(string), valueType);
if (!genericType.IsAssignableFrom(sourceType)) if (!genericType.IsAssignableFrom(type))
{ {
return null; return null;
} }
Type upcastType = typeof(UpcastDictionary<>).MakeGenericType(valueType); return valueType;
return (IDictionary<string, object>)Activator.CreateInstance(upcastType, source);
} }
} }