Commit b73acfce authored by vosen's avatar vosen

Add support for types with constructors matching the types pulled by data reader.

parent f97241e5
...@@ -1497,12 +1497,31 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1497,12 +1497,31 @@ static List<FieldInfo> GetSettableFields(Type t)
int index = startBound; int index = startBound;
ConstructorInfo specializedConstructor = null;
if (type.IsValueType) if (type.IsValueType)
{ {
il.Emit(OpCodes.Ldloca_S, (byte)1); il.Emit(OpCodes.Ldloca_S, (byte)1);
il.Emit(OpCodes.Initobj, type); il.Emit(OpCodes.Initobj, type);
} }
else else
{
var types = new Type[length - startBound];
for (int i = startBound; i < startBound + length; i++)
{
types[i - startBound] = reader.GetFieldType(i);
}
var ctorWithParameters = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, types, null);
if (ctorWithParameters != null)
{
var ctorParams = ctorWithParameters.GetParameters();
for(int i =0; i< ctorParams.Length; i++)
{
if (!String.Equals(ctorParams[i].Name, names[i], StringComparison.OrdinalIgnoreCase))
break;
specializedConstructor = ctorWithParameters;
}
}
if(specializedConstructor == null)
{ {
var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
if (ctor == null) if (ctor == null)
...@@ -1512,11 +1531,13 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1512,11 +1531,13 @@ static List<FieldInfo> GetSettableFields(Type t)
il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Stloc_1);
} }
}
il.BeginExceptionBlock(); il.BeginExceptionBlock();
if(type.IsValueType) if(type.IsValueType)
{ {
il.Emit(OpCodes.Ldloca_S, (byte)1);// [target] il.Emit(OpCodes.Ldloca_S, (byte)1);// [target]
} else }
else if(specializedConstructor == null)
{ {
il.Emit(OpCodes.Ldloc_1);// [target] il.Emit(OpCodes.Ldloc_1);// [target]
} }
...@@ -1529,6 +1550,7 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1529,6 +1550,7 @@ static List<FieldInfo> GetSettableFields(Type t)
{ {
if (item.Property != null || item.Field != null) if (item.Property != null || item.Field != null)
{ {
if(specializedConstructor == null)
il.Emit(OpCodes.Dup); // stack is now [target][target] il.Emit(OpCodes.Dup); // stack is now [target][target]
Label isDbNullLabel = il.DefineLabel(); Label isDbNullLabel = il.DefineLabel();
Label finishLabel = il.DefineLabel(); Label finishLabel = il.DefineLabel();
...@@ -1587,6 +1609,8 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1587,6 +1609,8 @@ static List<FieldInfo> GetSettableFields(Type t)
{ {
il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType })); il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));
} }
if (specializedConstructor == null)
{
if (item.Property != null) if (item.Property != null)
{ {
il.Emit(OpCodes.Callvirt, item.Property.Setter); // stack is now [target] il.Emit(OpCodes.Callvirt, item.Property.Setter); // stack is now [target]
...@@ -1595,6 +1619,7 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1595,6 +1619,7 @@ static List<FieldInfo> GetSettableFields(Type t)
{ {
il.Emit(OpCodes.Stfld, item.Field); // stack is now [target] il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]
} }
}
il.Emit(OpCodes.Br_S, finishLabel); il.Emit(OpCodes.Br_S, finishLabel);
...@@ -1614,6 +1639,8 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1614,6 +1639,8 @@ static List<FieldInfo> GetSettableFields(Type t)
il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType })); il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));
} }
} }
if (specializedConstructor == null)
{
if (item.Property != null) if (item.Property != null)
{ {
if (type.IsValueType) if (type.IsValueType)
...@@ -1629,13 +1656,24 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1629,13 +1656,24 @@ static List<FieldInfo> GetSettableFields(Type t)
{ {
il.Emit(OpCodes.Stfld, item.Field); // stack is now [target] il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]
} }
}
il.Emit(OpCodes.Br_S, finishLabel); // stack is now [target] il.Emit(OpCodes.Br_S, finishLabel); // stack is now [target]
il.MarkLabel(isDbNullLabel); // incoming stack: [target][target][value] il.MarkLabel(isDbNullLabel); // incoming stack: [target][target][value]
if (specializedConstructor != null)
{
Type itemType = item.Property != null ? item.Property.Type : item.Field.FieldType;
if (itemType.IsValueType)
il.Emit(OpCodes.Initobj, itemType);
else
il.Emit(OpCodes.Ldnull);
}
else
{
il.Emit(OpCodes.Pop); // stack is now [target][target] il.Emit(OpCodes.Pop); // stack is now [target][target]
il.Emit(OpCodes.Pop); // stack is now [target] il.Emit(OpCodes.Pop); // stack is now [target]
}
if (first && returnNullIfFirstMissing) if (first && returnNullIfFirstMissing)
{ {
...@@ -1656,6 +1694,10 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1656,6 +1694,10 @@ static List<FieldInfo> GetSettableFields(Type t)
} }
else else
{ {
if (specializedConstructor != null)
{
il.Emit(OpCodes.Newobj, specializedConstructor);
}
il.Emit(OpCodes.Stloc_1); // stack is empty il.Emit(OpCodes.Stloc_1); // stack is empty
} }
il.MarkLabel(allDone); il.MarkLabel(allDone);
......
...@@ -33,29 +33,21 @@ public class ConcreteOrder : Order ...@@ -33,29 +33,21 @@ public class ConcreteOrder : Order
} }
} }
class NoDefualtConstructor class NoDefaultConstructor
{ {
public NoDefualtConstructor(int a) public NoDefaultConstructor(int a)
{ {
A = a; A = a;
} }
public int A { get; set; } public int A { get; set; }
} }
public void EnsureNoConstructorGivesNiceError() public void TestNoDefaultConstructor()
{ {
try NoDefaultConstructor nodef = connection.Query<NoDefaultConstructor>("select 1 A").First();
{ nodef.A.IsEqualTo(1);
connection.Query<NoDefualtConstructor>("select 1 A").First();
}
catch(InvalidOperationException e)
{
e.Message.IsEqualTo("A parameterless default constructor is required to allow for dapper materialization");
} }
}
// http://stackoverflow.com/q/8593871 // http://stackoverflow.com/q/8593871
public void TestAbstractInheritance() public void TestAbstractInheritance()
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment