Commit a5c0295c authored by mgravell's avatar mgravell

less <T>, to avoid TargetInvoke woe

parent 432ae180
...@@ -107,8 +107,8 @@ private Link(TKey key, TValue value, Link<TKey, TValue> tail) ...@@ -107,8 +107,8 @@ private Link(TKey key, TValue value, Link<TKey, TValue> tail)
} }
class CacheInfo class CacheInfo
{ {
public object Deserializer { get; set; } public Func<IDataReader, object> Deserializer { get; set; }
public object[] OtherDeserializers { get; set; } public Func<IDataReader, object>[] OtherDeserializers { get; set; }
public Action<IDbCommand, object> ParamReader { get; set; } public Action<IDbCommand, object> ParamReader { get; set; }
private int hitCount; private int hitCount;
public int GetHitCount() { return Interlocked.CompareExchange(ref hitCount, 0, 0); } public int GetHitCount() { return Interlocked.CompareExchange(ref hitCount, 0, 0); }
...@@ -506,11 +506,11 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq ...@@ -506,11 +506,11 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
{ {
using (var reader = cmd.ExecuteReader()) using (var reader = cmd.ExecuteReader())
{ {
Func<Func<IDataReader, T>> cacheDeserializer = () => Func<Func<IDataReader, object>> cacheDeserializer = () =>
{ {
info.Deserializer = GetDeserializer<T>(reader, 0, -1, false); info.Deserializer = GetDeserializer(typeof(T), reader, 0, -1, false);
SetQueryCache(identity, info); SetQueryCache(identity, info);
return (Func<IDataReader, T>)info.Deserializer; return info.Deserializer;
}; };
if (info.Deserializer == null) if (info.Deserializer == null)
...@@ -518,11 +518,11 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq ...@@ -518,11 +518,11 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
cacheDeserializer(); cacheDeserializer();
} }
var deserializer = (Func<IDataReader, T>)info.Deserializer; var deserializer = info.Deserializer;
while (reader.Read()) while (reader.Read())
{ {
T next; object next;
try try
{ {
next = deserializer(reader); next = deserializer(reader);
...@@ -533,7 +533,7 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq ...@@ -533,7 +533,7 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
deserializer = cacheDeserializer(); deserializer = cacheDeserializer();
next = deserializer(reader); next = deserializer(reader);
} }
yield return next; yield return (T)next;
} }
} }
...@@ -617,8 +617,8 @@ class DontMap { } ...@@ -617,8 +617,8 @@ class DontMap { }
ownedReader = ownedCommand.ExecuteReader(); ownedReader = ownedCommand.ExecuteReader();
reader = ownedReader; reader = ownedReader;
} }
object deserializer = null; Func<IDataReader, object> deserializer = null;
object[] otherDeserializers = null; Func<IDataReader, object>[] otherDeserializers = null;
Action cacheDeserializers = () => Action cacheDeserializers = () =>
{ {
...@@ -673,50 +673,26 @@ class DontMap { } ...@@ -673,50 +673,26 @@ class DontMap { }
} }
} }
private static Func<IDataReader, TReturn> GenerateMapper<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(object deserializer, object[] otherDeserializers, object map) private static Func<IDataReader, TReturn> GenerateMapper<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(Func<IDataReader, object> deserializer, Func<IDataReader, object>[] otherDeserializers, object map)
{ {
var rootDeserializer = (Func<IDataReader, TFirst>)deserializer; switch(otherDeserializers.Length)
var deserializer2 = (Func<IDataReader, TSecond>)otherDeserializers[0]; {
case 1:
Func<IDataReader, TReturn> mapIt = null; return r => ((Func<TFirst, TSecond, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r));
case 2:
if (otherDeserializers.Length == 1) return r => ((Func<TFirst, TSecond, TThird, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r));
{ case 3:
mapIt = r => ((Func<TFirst, TSecond, TReturn>)map)(rootDeserializer(r), deserializer2(r)); return r => ((Func<TFirst, TSecond, TThird, TFourth, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r));
} #if !CSHARP30
case 4:
if (otherDeserializers.Length > 1) return r => ((Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>)map)((TFirst)deserializer(r), (TSecond)otherDeserializers[0](r), (TThird)otherDeserializers[1](r), (TFourth)otherDeserializers[2](r), (TFifth)otherDeserializers[3](r));
{
var deserializer3 = (Func<IDataReader, TThird>)otherDeserializers[1];
if (otherDeserializers.Length == 2)
{
mapIt = r => ((Func<TFirst, TSecond, TThird, TReturn>)map)(rootDeserializer(r), deserializer2(r), deserializer3(r));
}
if (otherDeserializers.Length > 2)
{
var deserializer4 = (Func<IDataReader, TFourth>)otherDeserializers[2];
if (otherDeserializers.Length == 3)
{
mapIt = r => ((Func<TFirst, TSecond, TThird, TFourth, TReturn>)map)(rootDeserializer(r), deserializer2(r), deserializer3(r), deserializer4(r));
}
if (otherDeserializers.Length > 3)
{
#if CSHARP30
throw new NotSupportedException();
#else
var deserializer5 = (Func<IDataReader, TFifth>)otherDeserializers[3];
mapIt = r => ((Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>)map)(rootDeserializer(r), deserializer2(r), deserializer3(r), deserializer4(r), deserializer5(r));
#endif #endif
} default:
} throw new NotSupportedException();
} }
return mapIt;
} }
private static object[] GenerateDeserializers(Type[] types, string splitOn, IDataReader reader) private static Func<IDataReader, object>[] GenerateDeserializers(Type[] types, string splitOn, IDataReader reader)
{ {
int current = 0; int current = 0;
var splits = splitOn.Split(',').ToArray(); var splits = splitOn.Split(',').ToArray();
...@@ -774,7 +750,7 @@ private static object[] GenerateDeserializers(Type[] types, string splitOn, IDat ...@@ -774,7 +750,7 @@ private static object[] GenerateDeserializers(Type[] types, string splitOn, IDat
return pos; return pos;
}; };
var deserializers = new List<object>(); var deserializers = new List<Func<IDataReader, object>>();
int split = 0; int split = 0;
bool first = true; bool first = true;
foreach (var type in types) foreach (var type in types)
...@@ -813,52 +789,22 @@ private static CacheInfo GetCacheInfo(Identity identity) ...@@ -813,52 +789,22 @@ private static CacheInfo GetCacheInfo(Identity identity)
return info; return info;
} }
static MethodInfo getDeserializerMethodInfo; private static Func<IDataReader, object> GetDeserializer(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
private static object GetDeserializer(Type t, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
{
if (getDeserializerMethodInfo == null)
{
foreach (var mi in typeof(SqlMapper).GetMethods(BindingFlags.NonPublic | BindingFlags.Static))
{
if (mi.Name == "GetDeserializer" && mi.IsGenericMethodDefinition)
{
getDeserializerMethodInfo = mi;
}
}
}
var method = getDeserializerMethodInfo.MakeGenericMethod(t);
try
{
return method.Invoke(null, new object[] { reader, startBound, length, returnNullIfFirstMissing });
}
catch (TargetInvocationException ex)
{
if (ex.InnerException != null && ex.InnerException.GetType() == typeof(ArgumentException))
{
throw ex.InnerException;
}
throw;
}
}
private static Func<IDataReader, T> GetDeserializer<T>(IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
{ {
Type type = typeof(T);
#if !CSHARP30 #if !CSHARP30
// dynamic is passed in as Object ... by c# design // dynamic is passed in as Object ... by c# design
if (type == typeof(object) if (type == typeof(object)
|| type == typeof(FastExpando)) || type == typeof(FastExpando))
{ {
return GetDynamicDeserializer<T>(reader, startBound, length, returnNullIfFirstMissing); return GetDynamicDeserializer(reader, startBound, length, returnNullIfFirstMissing);
} }
#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))
{ {
return GetClassDeserializer<T>(reader, startBound, length, returnNullIfFirstMissing); return GetClassDeserializer(type, reader, startBound, length, returnNullIfFirstMissing);
} }
return GetStructDeserializer<T>(startBound); return GetStructDeserializer(type, startBound);
} }
#if !CSHARP30 #if !CSHARP30
...@@ -987,7 +933,7 @@ IEnumerator IEnumerable.GetEnumerator() ...@@ -987,7 +933,7 @@ IEnumerator IEnumerable.GetEnumerator()
} }
private static Func<IDataReader, T> GetDynamicDeserializer<T>(IDataRecord reader, int startBound, int length, bool returnNullIfFirstMissing) private static Func<IDataReader, object> GetDynamicDeserializer(IDataRecord reader, int startBound, int length, bool returnNullIfFirstMissing)
{ {
var fieldCount = reader.FieldCount; var fieldCount = reader.FieldCount;
if (length == -1) if (length == -1)
...@@ -1011,11 +957,11 @@ IEnumerator IEnumerable.GetEnumerator() ...@@ -1011,11 +957,11 @@ IEnumerator IEnumerable.GetEnumerator()
row[r.GetName(i)] = tmp; row[r.GetName(i)] = tmp;
if (returnNullIfFirstMissing && i == startBound && tmp == null) if (returnNullIfFirstMissing && i == startBound && tmp == null)
{ {
return default(T); return null;
} }
} }
//we know this is an object so it will not box //we know this is an object so it will not box
return (T)(object)FastExpando.Attach(row); return FastExpando.Attach(row);
}; };
} }
#endif #endif
...@@ -1276,31 +1222,27 @@ private static int ExecuteCommand(IDbConnection cnn, IDbTransaction tranaction, ...@@ -1276,31 +1222,27 @@ private static int ExecuteCommand(IDbConnection cnn, IDbTransaction tranaction,
} }
} }
private static Func<IDataReader, T> GetStructDeserializer<T>(int index) private static Func<IDataReader, object> GetStructDeserializer(Type type, int index)
{ {
// no point using special per-type handling here; it boils down to the same, plus not all are supported anyway (see: SqlDataReader.GetChar - not supported!) // no point using special per-type handling here; it boils down to the same, plus not all are supported anyway (see: SqlDataReader.GetChar - not supported!)
#pragma warning disable 618 #pragma warning disable 618
if (typeof(T) == typeof(char)) if (type == typeof(char))
{ // this *does* need special handling, though { // this *does* need special handling, though
return (Func<IDataReader, T>)(object)new Func<IDataReader, char>(r => SqlMapper.ReadChar(r.GetValue(index))); return r => SqlMapper.ReadChar(r.GetValue(index));
} }
if (typeof(T) == typeof(char?)) if (type == typeof(char?))
{ {
return (Func<IDataReader, T>)(object)new Func<IDataReader, char?>(r => SqlMapper.ReadNullableChar(r.GetValue(index))); return r => SqlMapper.ReadNullableChar(r.GetValue(index));
} }
if (typeof(T) == typeof(System.Data.Linq.Binary)) if (type == typeof(System.Data.Linq.Binary))
{ {
return (Func<IDataReader, T>)(object)new Func<IDataReader, System.Data.Linq.Binary>(r => new System.Data.Linq.Binary((byte[])r.GetValue(index))); return r => new System.Data.Linq.Binary((byte[])r.GetValue(index));
} }
#pragma warning restore 618 #pragma warning restore 618
return r => return r =>
{ {
var val = r.GetValue(index); var val = r.GetValue(index);
if (val == DBNull.Value) return val is DBNull ? null : val;
{
val = null;
}
return (T)val;
}; };
} }
...@@ -1336,24 +1278,24 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1336,24 +1278,24 @@ static List<FieldInfo> GetSettableFields(Type t)
return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList(); return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList();
} }
public static Func<IDataReader, T> GetClassDeserializer<T>( public static Func<IDataReader, object> GetClassDeserializer(
#if CSHARP30 #if CSHARP30
IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing
#else #else
IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false Type type, IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false
#endif #endif
) )
{ {
var dm = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), typeof(T), new[] { typeof(IDataReader) }, true); var dm = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), type, new[] { typeof(IDataReader) }, true);
var il = dm.GetILGenerator(); var il = dm.GetILGenerator();
il.DeclareLocal(typeof(int)); il.DeclareLocal(typeof(int));
il.DeclareLocal(typeof(T)); 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);
var properties = GetSettableProps(typeof(T)); var properties = GetSettableProps(type);
var fields = GetSettableFields(typeof(T)); var fields = GetSettableFields(type);
if (length == -1) if (length == -1)
{ {
length = reader.FieldCount - startBound; length = reader.FieldCount - startBound;
...@@ -1384,7 +1326,7 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1384,7 +1326,7 @@ static List<FieldInfo> GetSettableFields(Type t)
il.BeginExceptionBlock(); il.BeginExceptionBlock();
// stack is empty // stack is empty
il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null)); // stack is now [target] 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)
...@@ -1519,7 +1461,7 @@ static List<FieldInfo> GetSettableFields(Type t) ...@@ -1519,7 +1461,7 @@ static List<FieldInfo> GetSettableFields(Type t)
il.Emit(OpCodes.Ldloc_1); // stack is empty il.Emit(OpCodes.Ldloc_1); // stack is empty
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
return (Func<IDataReader, T>)dm.CreateDelegate(typeof(Func<IDataReader, T>)); return (Func<IDataReader, object>)dm.CreateDelegate(typeof(Func<IDataReader,object>));
} }
public static void ThrowDataException(Exception ex, int index, IDataReader reader) public static void ThrowDataException(Exception ex, int index, IDataReader reader)
{ {
...@@ -1587,11 +1529,11 @@ public IEnumerable<T> Read<T>() ...@@ -1587,11 +1529,11 @@ public IEnumerable<T> Read<T>()
if (consumed) throw new InvalidOperationException("Each grid can only be iterated once"); if (consumed) throw new InvalidOperationException("Each grid can only be iterated once");
var typedIdentity = identity.ForGrid(typeof(T), gridIndex); var typedIdentity = identity.ForGrid(typeof(T), gridIndex);
CacheInfo cache = GetCacheInfo(typedIdentity); CacheInfo cache = GetCacheInfo(typedIdentity);
var deserializer = (Func<IDataReader, T>)cache.Deserializer; var deserializer = cache.Deserializer;
Func<Func<IDataReader, T>> deserializerGenerator = () => Func<Func<IDataReader, object>> deserializerGenerator = () =>
{ {
deserializer = GetDeserializer<T>(reader, 0, -1, false); deserializer = GetDeserializer(typeof(T), reader, 0, -1, false);
cache.Deserializer = deserializer; cache.Deserializer = deserializer;
return deserializer; return deserializer;
}; };
...@@ -1601,7 +1543,7 @@ public IEnumerable<T> Read<T>() ...@@ -1601,7 +1543,7 @@ public IEnumerable<T> Read<T>()
deserializer = deserializerGenerator(); deserializer = deserializerGenerator();
} }
consumed = true; consumed = true;
return ReadDeferred(gridIndex, deserializer, typedIdentity, deserializerGenerator); return ReadDeferred<T>(gridIndex, deserializer, typedIdentity, deserializerGenerator);
} }
private IEnumerable<TReturn> MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(object func, string splitOn) private IEnumerable<TReturn> MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(object func, string splitOn)
...@@ -1662,13 +1604,13 @@ public IEnumerable<T> Read<T>() ...@@ -1662,13 +1604,13 @@ public IEnumerable<T> Read<T>()
} }
#endif #endif
private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, T> deserializer, Identity typedIdentity, Func<Func<IDataReader, T>> deserializerGenerator) private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, object> deserializer, Identity typedIdentity, Func<Func<IDataReader, object>> deserializerGenerator)
{ {
try try
{ {
while (index == gridIndex && reader.Read()) while (index == gridIndex && reader.Read())
{ {
T next; object next;
try try
{ {
next = deserializer(reader); next = deserializer(reader);
...@@ -1678,7 +1620,7 @@ private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, T> deseriali ...@@ -1678,7 +1620,7 @@ private IEnumerable<T> ReadDeferred<T>(int index, Func<IDataReader, T> deseriali
deserializer = deserializerGenerator(); deserializer = deserializerGenerator();
next = deserializer(reader); next = deserializer(reader);
} }
yield return next; yield return (T)next;
} }
} }
finally // finally so that First etc progresses things even when multiple rows finally // finally so that First etc progresses things even when multiple rows
......
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