提交 b73acfce 编写于 作者: V vosen

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

上级 f97241e5
...@@ -1497,6 +1497,7 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1497,6 +1497,7 @@ 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);
...@@ -1504,19 +1505,39 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1504,19 +1505,39 @@ static List<FieldInfo> GetSettableFields(Type t)
} }
else else
{ {
var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); var types = new Type[length - startBound];
if (ctor == null) for (int i = startBound; i < startBound + length; i++)
{ {
throw new InvalidOperationException("A parameterless default constructor is required to allow for dapper materialization"); 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);
if (ctor == null)
{
throw new InvalidOperationException("A parameterless default constructor is required to allow for dapper materialization");
}
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_1);
} }
il.Emit(OpCodes.Newobj, ctor);
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,7 +1550,8 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1529,7 +1550,8 @@ static List<FieldInfo> GetSettableFields(Type t)
{ {
if (item.Property != null || item.Field != null) if (item.Property != null || item.Field != null)
{ {
il.Emit(OpCodes.Dup); // stack is now [target][target] if(specializedConstructor == null)
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,13 +1609,16 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1587,13 +1609,16 @@ static List<FieldInfo> GetSettableFields(Type t)
{ {
il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType })); il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));
} }
if (item.Property != null) if (specializedConstructor == null)
{
il.Emit(OpCodes.Callvirt, item.Property.Setter); // stack is now [target]
}
else
{ {
il.Emit(OpCodes.Stfld, item.Field); // stack is now [target] if (item.Property != null)
{
il.Emit(OpCodes.Callvirt, item.Property.Setter); // stack is now [target]
}
else
{
il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]
}
} }
il.Emit(OpCodes.Br_S, finishLabel); il.Emit(OpCodes.Br_S, finishLabel);
...@@ -1614,28 +1639,41 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1614,28 +1639,41 @@ static List<FieldInfo> GetSettableFields(Type t)
il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType })); il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType }));
} }
} }
if (item.Property != null) if (specializedConstructor == null)
{ {
if (type.IsValueType) if (item.Property != null)
{ {
il.Emit(OpCodes.Call, item.Property.Setter); // stack is now [target] if (type.IsValueType)
{
il.Emit(OpCodes.Call, item.Property.Setter); // stack is now [target]
}
else
{
il.Emit(OpCodes.Callvirt, item.Property.Setter); // stack is now [target]
}
} }
else else
{ {
il.Emit(OpCodes.Callvirt, item.Property.Setter); // stack is now [target] il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]
} }
} }
else
{
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)
il.Emit(OpCodes.Pop); // stack is now [target][target] {
il.Emit(OpCodes.Pop); // stack is now [target] 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]
}
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% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册