Commit 6d16ac8f authored by Sam Saffron's avatar Sam Saffron

Add struct support to dapper

parent e5102341
...@@ -926,10 +926,14 @@ private static CacheInfo GetCacheInfo(Identity identity) ...@@ -926,10 +926,14 @@ private static CacheInfo GetCacheInfo(Identity identity)
} }
#endif #endif
if (type.IsClass && type != typeof(string) && type != typeof(byte[]) && type != typeof(System.Data.Linq.Binary)) if (
(type.IsClass && type != typeof(string) && type != typeof(byte[]) && type != typeof(System.Data.Linq.Binary)) ||
(type.IsValueType && !type.IsPrimitive && !(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)))
)
{ {
return GetClassDeserializer(type, reader, startBound, length, returnNullIfFirstMissing); return GetTypeDeserializer(type, reader, startBound, length, returnNullIfFirstMissing);
} }
return GetStructDeserializer(type, startBound); return GetStructDeserializer(type, startBound);
} }
...@@ -1437,7 +1441,7 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1437,7 +1441,7 @@ static List<FieldInfo> GetSettableFields(Type t)
/// <param name="length"></param> /// <param name="length"></param>
/// <param name="returnNullIfFirstMissing"></param> /// <param name="returnNullIfFirstMissing"></param>
/// <returns></returns> /// <returns></returns>
public static Func<IDataReader, object> GetClassDeserializer( public static Func<IDataReader, object> GetTypeDeserializer(
#if CSHARP30 #if CSHARP30
Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing
#else #else
...@@ -1445,11 +1449,11 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1445,11 +1449,11 @@ static List<FieldInfo> GetSettableFields(Type t)
#endif #endif
) )
{ {
var dm = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), type, new[] { typeof(IDataReader) }, true); var dm = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), type.IsValueType ? typeof(object) : type, new[] { typeof(IDataReader) }, true);
var il = dm.GetILGenerator(); var il = dm.GetILGenerator();
il.DeclareLocal(typeof(int)); il.DeclareLocal(typeof(int));
il.DeclareLocal(type); var emptyLocal = il.DeclareLocal(type);
bool haveEnumLocal = false; bool haveEnumLocal = false;
il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Stloc_0);
...@@ -1485,7 +1489,20 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1485,7 +1489,20 @@ static List<FieldInfo> GetSettableFields(Type t)
il.BeginExceptionBlock(); il.BeginExceptionBlock();
// stack is empty // stack is empty
il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null)); // stack is now [target]
if (type.IsValueType)
{
il.Emit(OpCodes.Ldloca, emptyLocal);
il.Emit(OpCodes.Initobj, type);
il.Emit(OpCodes.Ldloca, emptyLocal);
}
else
{
il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
}
// stack is now [target]
bool first = true; bool first = true;
var allDone = il.DefineLabel(); var allDone = il.DefineLabel();
foreach (var item in setters) foreach (var item in setters)
...@@ -1502,7 +1519,6 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1502,7 +1519,6 @@ static List<FieldInfo> GetSettableFields(Type t)
il.Emit(OpCodes.Stloc_0);// stack is now [target][target][reader][index] il.Emit(OpCodes.Stloc_0);// stack is now [target][target][reader][index]
il.Emit(OpCodes.Callvirt, getItem); // stack is now [target][target][value-as-object] il.Emit(OpCodes.Callvirt, getItem); // stack is now [target][target][value-as-object]
Type memberType = item.Property != null ? item.Property.Type : item.Field.FieldType; Type memberType = item.Property != null ? item.Property.Type : item.Field.FieldType;
if (memberType == typeof(char) || memberType == typeof(char?)) if (memberType == typeof(char) || memberType == typeof(char?))
...@@ -1579,9 +1595,16 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1579,9 +1595,16 @@ static List<FieldInfo> GetSettableFields(Type t)
} }
} }
if (item.Property != null) if (item.Property != null)
{
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] il.Emit(OpCodes.Callvirt, item.Property.Setter); // stack is now [target]
} }
}
else else
{ {
il.Emit(OpCodes.Stfld, item.Field); // stack is now [target] il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]
...@@ -1607,7 +1630,14 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1607,7 +1630,14 @@ static List<FieldInfo> GetSettableFields(Type t)
first = false; first = false;
index += 1; index += 1;
} }
if (type.IsValueType)
{
il.Emit(OpCodes.Pop);
}
else
{
il.Emit(OpCodes.Stloc_1); // stack is empty il.Emit(OpCodes.Stloc_1); // stack is empty
}
il.MarkLabel(allDone); il.MarkLabel(allDone);
il.BeginCatchBlock(typeof(Exception)); // stack is Exception il.BeginCatchBlock(typeof(Exception)); // stack is Exception
il.Emit(OpCodes.Ldloc_0); // stack is Exception, index il.Emit(OpCodes.Ldloc_0); // stack is Exception, index
...@@ -1617,7 +1647,16 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1617,7 +1647,16 @@ static List<FieldInfo> GetSettableFields(Type t)
il.Emit(OpCodes.Stloc_1); // to make it verifiable il.Emit(OpCodes.Stloc_1); // to make it verifiable
il.EndExceptionBlock(); il.EndExceptionBlock();
il.Emit(OpCodes.Ldloc_1); // stack is empty
if (type.IsValueType)
{
il.Emit(OpCodes.Ldloc, emptyLocal); // stack is [rval]
il.Emit(OpCodes.Box, type);
}
else
{
il.Emit(OpCodes.Ldloc_1); // stack is [rval]
}
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
return (Func<IDataReader, object>)dm.CreateDelegate(typeof(Func<IDataReader,object>)); return (Func<IDataReader, object>)dm.CreateDelegate(typeof(Func<IDataReader,object>));
......
...@@ -16,6 +16,28 @@ class Tests ...@@ -16,6 +16,28 @@ class Tests
{ {
SqlConnection connection = Program.GetOpenConnection(); SqlConnection connection = Program.GetOpenConnection();
struct Car
{
public enum TrapEnum : int
{
A = 1,
B = 2
}
public string Name;
public int Age { get; set; }
public TrapEnum Trap { get; set; }
}
public void TestStructs()
{
var car = connection.Query<Car>("select 'Ford' Name, 21 Age, 2 Trap").First();
car.Age.IsEqualTo(21);
car.Name.IsEqualTo("Ford");
((int)car.Trap).IsEqualTo(2);
}
public void SelectListInt() public void SelectListInt()
{ {
connection.Query<int>("select 1 union all select 2 union all select 3") connection.Query<int>("select 1 union all select 2 union all select 3")
...@@ -1111,5 +1133,6 @@ public void TestAppendingAList() ...@@ -1111,5 +1133,6 @@ public void TestAppendingAList()
result[1].IsEqualTo(2); result[1].IsEqualTo(2);
result[2].IsEqualTo(3); result[2].IsEqualTo(3);
} }
} }
} }
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