public Delegate GetFactory(int firstColumn, int countColumns, IDataReader r, object instance) { //Create a hashed key, we don't want to store so much string data in memory var combiner = new HashCodeCombiner("mapping"); combiner.AddType(_pocoData.type); combiner.AddInt(firstColumn); combiner.AddInt(countColumns); for (int col = 0; col < r.FieldCount; col++) { combiner.AddType(r.GetFieldType(col)); combiner.AddCaseInsensitiveString(r.GetName(col)); } combiner.AddBool(instance != GetDefault(_pocoData.type)); combiner.AddBool(_pocoData.EmptyNestedObjectNull); var key = combiner.GetCombinedHashCode(); Func <Delegate> createFactory = () => { // Create the method var m = new DynamicMethod("poco_factory_" + _pocoFactories.Count, _pocoData.type, new Type[] { typeof(IDataReader), _pocoData.type }, true); var il = m.GetILGenerator(); #if !POCO_NO_DYNAMIC if (_pocoData.type == typeof(object)) { // var poco=new T() il.Emit(OpCodes.Newobj, typeof(PocoExpando).GetConstructor(Type.EmptyTypes)); // obj MethodInfo fnAdd = typeof(IDictionary <string, object>).GetMethod("Add"); // Enumerate all fields generating a set assignment for the column for (int i = firstColumn; i < firstColumn + countColumns; i++) { var srcType = r.GetFieldType(i); il.Emit(OpCodes.Dup); // obj, obj il.Emit(OpCodes.Ldstr, r.GetName(i)); // obj, obj, fieldname // Get the converter Func <object, object> converter = null; if (_pocoData.Mapper != null) { converter = _pocoData.Mapper.GetFromDbConverter((Type)null, srcType); } //if (ForceDateTimesToUtc && converter == null && srcType == typeof(DateTime)) // converter = delegate(object src) { return new DateTime(((DateTime)src).Ticks, DateTimeKind.Utc); }; // Setup stack for call to converter AddConverterToStack(il, converter); // r[i] il.Emit(OpCodes.Ldarg_0); // obj, obj, fieldname, converter?, rdr il.Emit(OpCodes.Ldc_I4, i); // obj, obj, fieldname, converter?, rdr,i il.Emit(OpCodes.Callvirt, fnGetValue); // obj, obj, fieldname, converter?, value // Convert DBNull to null il.Emit(OpCodes.Dup); // obj, obj, fieldname, converter?, value, value il.Emit(OpCodes.Isinst, typeof(DBNull)); // obj, obj, fieldname, converter?, value, (value or null) var lblNotNull = il.DefineLabel(); il.Emit(OpCodes.Brfalse_S, lblNotNull); // obj, obj, fieldname, converter?, value il.Emit(OpCodes.Pop); // obj, obj, fieldname, converter? if (converter != null) { il.Emit(OpCodes.Pop); // obj, obj, fieldname, } il.Emit(OpCodes.Ldnull); // obj, obj, fieldname, null if (converter != null) { var lblReady = il.DefineLabel(); il.Emit(OpCodes.Br_S, lblReady); il.MarkLabel(lblNotNull); il.Emit(OpCodes.Callvirt, fnInvoke); il.MarkLabel(lblReady); } else { il.MarkLabel(lblNotNull); } il.Emit(OpCodes.Callvirt, fnAdd); } } else #endif if (_pocoData.type.IsValueType || _pocoData.type == typeof(string) || _pocoData.type == typeof(byte[])) { // Do we need to install a converter? var srcType = r.GetFieldType(0); var converter = GetConverter(_pocoData.Mapper, null, srcType, _pocoData.type); // "if (!rdr.IsDBNull(i))" il.Emit(OpCodes.Ldarg_0); // rdr il.Emit(OpCodes.Ldc_I4_0); // rdr,0 il.Emit(OpCodes.Callvirt, fnIsDBNull); // bool var lblCont = il.DefineLabel(); il.Emit(OpCodes.Brfalse_S, lblCont); il.Emit(OpCodes.Ldnull); // null var lblFin = il.DefineLabel(); il.Emit(OpCodes.Br_S, lblFin); il.MarkLabel(lblCont); // Setup stack for call to converter AddConverterToStack(il, converter); il.Emit(OpCodes.Ldarg_0); // rdr il.Emit(OpCodes.Ldc_I4_0); // rdr,0 il.Emit(OpCodes.Callvirt, fnGetValue); // value // Call the converter if (converter != null) { il.Emit(OpCodes.Callvirt, fnInvoke); } il.MarkLabel(lblFin); il.Emit(OpCodes.Unbox_Any, _pocoData.type); // value converted } else if (_pocoData.type == typeof(Dictionary <string, object>)) { Func <IDataReader, object, Dictionary <string, object> > func = (reader, inst) => { var dict = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase); for (int i = firstColumn; i < firstColumn + countColumns; i++) { var value = reader.IsDBNull(i) ? null : reader.GetValue(i); var name = reader.GetName(i); if (!dict.ContainsKey(name)) { dict.Add(name, value); } } return(dict); }; var delegateType = typeof(Func <, ,>).MakeGenericType(typeof(IDataReader), _pocoData.type, typeof(Dictionary <string, object>)); var localDel = Delegate.CreateDelegate(delegateType, func.Target, func.Method); return(localDel); } else if (_pocoData.type.IsArray) { il.Emit(OpCodes.Ldc_I4_S, countColumns - firstColumn); il.Emit(OpCodes.Newarr, _pocoData.type.GetElementType()); var valueset = typeof(Array).GetMethod("SetValue", new[] { typeof(object), typeof(int) }); for (int i = firstColumn; i < firstColumn + countColumns; i++) { // "if (!rdr.IsDBNull(i))" il.Emit(OpCodes.Ldarg_0); // arr,rdr il.Emit(OpCodes.Ldc_I4, i); // arr,rdr,i il.Emit(OpCodes.Callvirt, fnIsDBNull); // arr,bool var lblNext = il.DefineLabel(); il.Emit(OpCodes.Brtrue_S, lblNext); // arr il.Emit(OpCodes.Dup); // arr,arr il.Emit(OpCodes.Ldarg_0); // arr,arr,rdr il.Emit(OpCodes.Ldc_I4, i - firstColumn); // arr,arr,rdr,i il.Emit(OpCodes.Callvirt, fnGetValue); // arr,arr,value il.Emit(OpCodes.Ldc_I4, i - firstColumn); // arr,arr,value,i il.Emit(OpCodes.Callvirt, valueset); // arr il.MarkLabel(lblNext); } il.Emit(OpCodes.Castclass, _pocoData.type); } else { if (instance != null) { il.Emit(OpCodes.Ldarg_1); } else { var constructorInfo = _pocoData.type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null); if (constructorInfo == null) { throw new Exception(string.Format("Poco '{0}' has no parameterless constructor", _pocoData.type.FullName)); } // var poco=new T() il.Emit(OpCodes.Newobj, constructorInfo); } LocalBuilder a = il.DeclareLocal(typeof(Int32)); if (_pocoData.EmptyNestedObjectNull) { il.Emit(OpCodes.Ldc_I4, 0); il.Emit(OpCodes.Stloc, a); } // Enumerate all fields generating a set assignment for the column for (int i = firstColumn; i < firstColumn + countColumns; i++) { // Get the PocoColumn for this db column, ignore if not known PocoColumn pc; if (!TryGetColumnByName(_pocoData.Columns, r.GetName(i), out pc) || (!pc.MemberInfo.IsField() && ((PropertyInfo)pc.MemberInfo).GetSetMethodOnDeclaringType() == null)) { var pcAlias = _pocoData.Columns.Values.SingleOrDefault(x => x.AutoAlias == r.GetName(i)) ?? _pocoData.Columns.Values.SingleOrDefault(x => string.Equals(x.ColumnAlias, r.GetName(i), StringComparison.OrdinalIgnoreCase)); if (pcAlias != null) { pc = pcAlias; } else { continue; } } // Get the source type for this column var srcType = r.GetFieldType(i); var dstType = pc.MemberInfo.GetMemberInfoType(); // "if (!rdr.IsDBNull(i))" il.Emit(OpCodes.Ldarg_0); // poco,rdr il.Emit(OpCodes.Ldc_I4, i); // poco,rdr,i il.Emit(OpCodes.Callvirt, fnIsDBNull); // poco,bool var lblNext = il.DefineLabel(); il.Emit(OpCodes.Brtrue_S, lblNext); // poco il.Emit(OpCodes.Dup); // poco,poco // Do we need to install a converter? var converter = GetConverter(_pocoData.Mapper, pc, srcType, dstType); // Fast bool Handled = false; if (converter == null) { var valuegetter = typeof(IDataRecord).GetMethod("Get" + srcType.Name, new Type[] { typeof(int) }); if (valuegetter != null && valuegetter.ReturnType == srcType && (valuegetter.ReturnType == dstType || valuegetter.ReturnType == Nullable.GetUnderlyingType(dstType))) { il.Emit(OpCodes.Ldarg_0); // *,rdr il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i il.Emit(OpCodes.Callvirt, valuegetter); // *,value // Convert to Nullable if (Nullable.GetUnderlyingType(dstType) != null) { il.Emit(OpCodes.Newobj, dstType.GetConstructor(new Type[] { Nullable.GetUnderlyingType(dstType) })); } PushMemberOntoStack(il, pc); //poco Handled = true; } } // Not so fast if (!Handled) { // Setup stack for call to converter AddConverterToStack(il, converter); // "value = rdr.GetValue(i)" il.Emit(OpCodes.Ldarg_0); // *,rdr il.Emit(OpCodes.Ldc_I4, i); // *,rdr,i il.Emit(OpCodes.Callvirt, fnGetValue); // *,value // Call the converter if (converter != null) { il.Emit(OpCodes.Callvirt, fnInvoke); } // Assign it il.Emit(OpCodes.Unbox_Any, pc.MemberInfo.GetMemberInfoType()); // poco,poco,value PushMemberOntoStack(il, pc); //poco } if (_pocoData.EmptyNestedObjectNull) { il.Emit(OpCodes.Ldloc, a); // poco, a il.Emit(OpCodes.Ldc_I4, 1); // poco, a, 1 il.Emit(OpCodes.Add); // poco, a+1 il.Emit(OpCodes.Stloc, a); // poco } il.MarkLabel(lblNext); } var fnOnLoaded = RecurseInheritedTypes <MethodInfo>(_pocoData.type, (x) => x.GetMethod("OnLoaded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null)); if (fnOnLoaded != null) { il.Emit(OpCodes.Dup); il.Emit(OpCodes.Callvirt, (MethodInfo)fnOnLoaded); } if (_pocoData.EmptyNestedObjectNull) { var lblNull = il.DefineLabel(); var lblElse = il.DefineLabel(); il.Emit(OpCodes.Ldc_I4_0); // poco, 0 il.Emit(OpCodes.Ldloc, a); // poco, 0, a il.Emit(OpCodes.Beq, lblNull); // poco il.Emit(OpCodes.Br_S, lblElse); il.MarkLabel(lblNull); il.Emit(OpCodes.Pop); // il.Emit(OpCodes.Ldnull); // null il.MarkLabel(lblElse); } } il.Emit(OpCodes.Ret); // Cache it, return it var del = m.CreateDelegate(Expression.GetFuncType(typeof(IDataReader), _pocoData.type, _pocoData.type)); return(del); }; var fac = _pocoFactories.Get(key, createFactory); return(fac); }