Permalink
Browse files

fix for nested collections that are not complex types.

  • Loading branch information...
1 parent 7e03029 commit b37894f62e6e16728a4c2a16c168241422f9a1c2 @craiggwilson craiggwilson committed Mar 30, 2012
Showing with 94 additions and 14 deletions.
  1. +23 −0 Simple.Data.UnitTest/SimpleResultSetTest.cs
  2. +71 −14 Simple.Data/PropertySetterBuilder.cs
@@ -392,10 +392,33 @@ public void CastToGenericCreatesTypedList()
Assert.AreEqual(1, converted.Count());
Assert.AreEqual("0", converted.First().Data);
}
+
+ [Test]
+ public void CastToGenericCreatesTypedListWithSubTypes()
+ {
+ var firstRecord = new SimpleRecord(new Dictionary<string, object>
+ {
+ { "Data", "First" },
+ { "List", new List<string> { "First-One", "First-Two" } }
+ });
+
+ var list = new SimpleResultSet(new List<dynamic> { firstRecord });
+
+ var result = list.Cast<TestType2>().First();
+
+ Assert.AreEqual(2, result.List.Count);
+ }
}
class TestType
{
public string Data { get; set; }
}
+
+ class TestType2
+ {
+ public string Data { get; set; }
+
+ public List<string> List { get; set; }
+ }
}
@@ -12,13 +12,21 @@ class PropertySetterBuilder
private static readonly MethodInfo DictionaryContainsKeyMethod = typeof(IDictionary<string, object>).GetMethod("ContainsKey", new[] { typeof(string) });
private static readonly PropertyInfo DictionaryIndexerProperty = typeof(IDictionary<string, object>).GetProperty("Item");
- private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetMethod("ToArray",
+ private static readonly MethodInfo ToArrayDictionaryMethod = typeof(Enumerable).GetMethod("ToArray",
BindingFlags.Public |
BindingFlags.Static).MakeGenericMethod(typeof(IDictionary<string, object>));
- private static readonly PropertyInfo ArrayLengthProperty =
+ private static readonly MethodInfo ToArrayObjectMethod = typeof(Enumerable).GetMethod("ToArray",
+ BindingFlags.Public |
+ BindingFlags.Static).MakeGenericMethod(typeof(object));
+
+
+ private static readonly PropertyInfo ArrayDictionaryLengthProperty =
typeof(IDictionary<string, object>[]).GetProperty("Length");
+ private static readonly PropertyInfo ArrayObjectLengthProperty =
+ typeof(object[]).GetProperty("Length");
+
private readonly ParameterExpression _param;
private readonly ParameterExpression _obj;
private readonly PropertyInfo _property;
@@ -84,11 +92,7 @@ private Expression BuildArrayCreator()
if (addMethod == null) return null;
- BlockExpression block;
- var isDictionaryCollection = BuildCollectionPopulator(collection, genericType, addMethod, createCollection,
- creatorInstance, out block);
-
- return Expression.IfThen(isDictionaryCollection, block);
+ return BuildCollectionCreatorExpression(genericType, creatorInstance, collection, createCollection, addMethod);
}
private Expression BuildCollectionCreator()
@@ -110,15 +114,24 @@ private Expression BuildCollectionCreator()
if (createCollection != null && addMethod != null)
{
- BlockExpression block;
- var isDictionaryCollection = BuildCollectionPopulator(collection, genericType, addMethod, createCollection, creatorInstance, out block);
-
- return Expression.IfThen(isDictionaryCollection, block);
+ return BuildCollectionCreatorExpression(genericType, creatorInstance, collection, createCollection, addMethod);
}
return null;
}
- private TypeBinaryExpression BuildCollectionPopulator(ParameterExpression collection, Type genericType,
+ private Expression BuildCollectionCreatorExpression(Type genericType, ConcreteTypeCreator creatorInstance, ParameterExpression collection, BinaryExpression createCollection, MethodInfo addMethod)
+ {
+ BlockExpression dictionaryBlock;
+ var isDictionaryCollection = BuildComplexTypeCollectionPopulator(collection, genericType, addMethod, createCollection, creatorInstance, out dictionaryBlock);
+
+ BlockExpression objectBlock;
+ var isObjectcollection = BuildSimpleTypeCollectionPopulator(collection, genericType, addMethod, createCollection, out objectBlock);
+
+ return Expression.IfThenElse(isDictionaryCollection, dictionaryBlock,
+ Expression.IfThen(isObjectcollection, objectBlock));
+ }
+
+ private TypeBinaryExpression BuildComplexTypeCollectionPopulator(ParameterExpression collection, Type genericType,
MethodInfo addMethod, BinaryExpression createCollection,
ConcreteTypeCreator creatorInstance, out BlockExpression block)
{
@@ -131,14 +144,14 @@ private Expression BuildCollectionCreator()
typeof (IEnumerable<IDictionary<string, object>>));
var toArray = Expression.Assign(array,
- Expression.Call(ToArrayMethod,
+ Expression.Call(ToArrayDictionaryMethod,
Expression.Convert(_itemProperty,
typeof (IEnumerable<IDictionary<string, object>>))));
var start = Expression.Assign(i, Expression.Constant(0));
var label = Expression.Label();
var loop = Expression.Loop(
Expression.IfThenElse(
- Expression.LessThan(i, Expression.Property(array, ArrayLengthProperty)),
+ Expression.LessThan(i, Expression.Property(array, ArrayDictionaryLengthProperty)),
Expression.Block(
Expression.Assign(current, Expression.ArrayIndex(array, i)),
Expression.Call(collection, addMethod,
@@ -161,6 +174,48 @@ private Expression BuildCollectionCreator()
return isDictionaryCollection;
}
+ private TypeBinaryExpression BuildSimpleTypeCollectionPopulator(ParameterExpression collection, Type genericType,
+ MethodInfo addMethod, BinaryExpression createCollection,
+ out BlockExpression block)
+ {
+ var array = Expression.Variable(typeof(object[]));
+ var i = Expression.Variable(typeof(int));
+ var current = Expression.Variable(typeof(object));
+
+ var isObjectCollection = Expression.TypeIs(_itemProperty,
+ typeof(IEnumerable<object>));
+
+ var toArray = Expression.Assign(array,
+ Expression.Call(ToArrayObjectMethod,
+ Expression.Convert(_itemProperty,
+ typeof(IEnumerable<object>))));
+ var start = Expression.Assign(i, Expression.Constant(0));
+ var label = Expression.Label();
+ var loop = Expression.Loop(
+ Expression.IfThenElse(
+ Expression.LessThan(i, Expression.Property(array, ArrayObjectLengthProperty)),
+ Expression.Block(
+ Expression.Assign(current, Expression.ArrayIndex(array, i)),
+ Expression.Call(collection, addMethod,
+ Expression.Convert(current, genericType)),
+ Expression.PreIncrementAssign(i)
+ ),
+ Expression.Break(label)
+ ),
+ label
+ );
+
+ block = Expression.Block(
+ new[] { array, i, collection, current },
+ createCollection,
+ toArray,
+ start,
+ loop,
+ _property.CanWrite ? (Expression)Expression.Assign(_nameProperty, collection) : Expression.Empty());
+
+ return isObjectCollection;
+ }
+
private BinaryExpression MakeCreateNewCollection(ParameterExpression collection, Type genericType)
{
BinaryExpression createCollection;
@@ -283,6 +338,8 @@ private TryExpression CreateTrySimpleArrayAssign()
assign), Expression.Catch(typeof(Exception), Expression.Empty()));
}
+
+
// ReSharper disable UnusedMember.Local
// Because they're used from runtime-generated code, you see.
private static object SafeConvert(object source, Type targetType)

0 comments on commit b37894f

Please sign in to comment.