Commit 6333ed16 authored by Marc Gravell's avatar Marc Gravell

Parameter reader should work for structs as well as classes; fixes issue #199

parent fb5dd93b
......@@ -2955,10 +2955,19 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
var il = dm.GetILGenerator();
il.DeclareLocal(type); // 0
bool isStruct = type.IsValueType;
bool haveInt32Arg1 = false;
il.Emit(OpCodes.Ldarg_1); // stack is now [untyped-param]
il.Emit(OpCodes.Unbox_Any, type); // stack is now [typed-param]
if (isStruct)
{
il.DeclareLocal(type.MakePointerType());
il.Emit(OpCodes.Unbox, type); // stack is now [typed-param]
}
else
{
il.DeclareLocal(type); // 0
il.Emit(OpCodes.Castclass, type); // stack is now [typed-param]
}
il.Emit(OpCodes.Stloc_0);// stack is now empty
il.Emit(OpCodes.Ldarg_0); // stack is now [command]
......@@ -3021,12 +3030,13 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
props = FilterParameters(props, identity.sql);
}
var callOpCode = isStruct ? OpCodes.Call : OpCodes.Callvirt;
foreach (var prop in props)
{
if (typeof(ICustomQueryParameter).IsAssignableFrom(prop.PropertyType))
{
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [typed-param]
il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [custom]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [custom]
il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [custom] [command]
il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [custom] [command] [name]
il.EmitCall(OpCodes.Callvirt, prop.PropertyType.GetMethod("AddParameter"), null); // stack is now [parameters]
......@@ -3040,7 +3050,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [command]
il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [command] [name]
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [command] [name] [typed-param]
il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [command] [name] [typed-value]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [command] [name] [typed-value]
if (prop.PropertyType.IsValueType)
{
il.Emit(OpCodes.Box, prop.PropertyType); // stack is [parameters] [command] [name] [boxed-value]
......@@ -3074,7 +3084,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
{
// look it up from the param value
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param]
il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [object-value]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [object-value]
il.Emit(OpCodes.Call, typeof(SqlMapper).GetMethod("GetDbType", BindingFlags.Static | BindingFlags.Public)); // stack is now [parameters] [[parameters]] [parameter] [parameter] [db-type]
}
else
......@@ -3091,7 +3101,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param]
il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [typed-value]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [typed-value]
bool checkForNull = true;
if (prop.PropertyType.IsValueType)
{
......@@ -3219,7 +3229,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
{
il.Emit(OpCodes.Ldstr, literal.Token);
il.Emit(OpCodes.Ldloc_0); // command, sql, typed parameter
il.EmitCall(OpCodes.Callvirt, prop.GetGetMethod(), null); // command, sql, typed value
il.EmitCall(callOpCode, prop.GetGetMethod(), null); // command, sql, typed value
Type propType = prop.PropertyType;
var typeCode = Type.GetTypeCode(propType);
switch (typeCode)
......
......@@ -293,6 +293,14 @@ public enum TrapEnum : int
}
struct CarWithAllProps
{
public string Name { get; set; }
public int Age { get; set; }
public Car.TrapEnum Trap { get; set; }
}
public void TestStructs()
{
var car = connection.Query<Car>("select 'Ford' Name, 21 Age, 2 Trap").First();
......@@ -302,6 +310,17 @@ public void TestStructs()
((int)car.Trap).IsEqualTo(2);
}
public void TestStructAsParam()
{
var car1 = new CarWithAllProps { Name = "Ford", Age = 21, Trap = Car.TrapEnum.B };
// note Car has Name as a field; parameters only respect properties at the moment
var car2 = connection.Query<CarWithAllProps>("select @Name Name, @Age Age, @Trap Trap", car1).First();
car2.Name.IsEqualTo(car1.Name);
car2.Age.IsEqualTo(car1.Age);
car2.Trap.IsEqualTo(car1.Trap);
}
public void SelectListInt()
{
connection.Query<int>("select 1 union all select 2 union all select 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