private static FuncGetTypeDeserializerImpl(
Type type, IDataReader reader,int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false)
{var returnType = type.IsValueType() ? typeof(object) : type;var dm = new DynamicMethod("Deserialize" + Guid.NewGuid().ToString(), returnType, new[] { typeof(IDataReader) }, type, true);var il =dm.GetILGenerator();
il.DeclareLocal(typeof(int));
il.DeclareLocal(type);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_0);if (length == -1)
{
length= reader.FieldCount -startBound;
}if (reader.FieldCount <=startBound)
{throwMultiMapException(reader);
}//数据库字段名
var fieldNames = Enumerable.Range(startBound, length).Select(i =>reader.GetName(i)).ToArray();//ITypeMap 含type的字段,属性
ITypeMap typeMap =GetTypeMap(type);int index =startBound;
ConstructorInfo specializedConstructor= null;#if !NETSTANDARD1_3
bool supportInitialize = false;#endifDictionary structLocals = null;if(type.IsValueType())
{
il.Emit(OpCodes.Ldloca_S, (byte)1);
il.Emit(OpCodes.Initobj, type);
}else{//字段映射,开始
var types = newType[length];for (int i = startBound; i < startBound + length; i++)
{
types[i- startBound] =reader.GetFieldType(i);
}//获取ExplicitConstructor特性的构造函数
var explicitConstr =typeMap.FindExplicitConstructor();if (explicitConstr != null)
{var consPs =explicitConstr.GetParameters();foreach (var p inconsPs)
{if (!p.ParameterType.IsValueType())
{
il.Emit(OpCodes.Ldnull);
}else{
GetTempLocal(il,ref structLocals, p.ParameterType, true);
}
}
il.Emit(OpCodes.Newobj, explicitConstr);
il.Emit(OpCodes.Stloc_1);#if !NETSTANDARD1_3supportInitialize= typeof(ISupportInitialize).IsAssignableFrom(type);if(supportInitialize)
{
il.Emit(OpCodes.Ldloc_1);
il.EmitCall(OpCodes.Callvirt,typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.BeginInit)), null);
}#endif}else{//按构造函数参数个数倒序排列,查找合适的构造函数
var ctor =typeMap.FindConstructor(fieldNames, types);if (ctor == null)
{string proposedTypes = "(" + string.Join(",", types.Select((t, i) => t.FullName + " " + fieldNames[i]).ToArray()) + ")";throw new InvalidOperationException($"A parameterless default constructor or one matching signature {proposedTypes} is required for {type.FullName} materialization");
}//无参构造
if (ctor.GetParameters().Length == 0)
{//用指定构造函数创建一个新实例,赋值给类型变量
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_1);#if !NETSTANDARD1_3supportInitialize= typeof(ISupportInitialize).IsAssignableFrom(type);if(supportInitialize)
{//取type实例
il.Emit(OpCodes.Ldloc_1);//调用公共方法
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.BeginInit)), null);
}#endif}else{
specializedConstructor=ctor;
}
}
}//try块开始
il.BeginExceptionBlock();//值类型
if(type.IsValueType())
{
il.Emit(OpCodes.Ldloca_S, (byte)1);//[target]
}else if (specializedConstructor == null)
{
il.Emit(OpCodes.Ldloc_1);//[target]
}//根据数据库字段名,查找传入类型中对应的属性Property,若没有则查找字段Field
var members = IsValueTuple(type) ? GetValueTupleMembers(type, fieldNames) : ((specializedConstructor != null
? fieldNames.Select(n =>typeMap.GetConstructorParameter(specializedConstructor, n))
: fieldNames.Select(n=>typeMap.GetMember(n))).ToList());//stack is now [target]
bool first = true;var allDone =il.DefineLabel();int enumDeclareLocal = -1, valueCopyLocal = il.DeclareLocal(typeof(object)).LocalIndex;bool applyNullSetting =Settings.ApplyNullValues;foreach (var item inmembers)
{if (item != null)
{if (specializedConstructor == null)
il.Emit(OpCodes.Dup);//stack is now [target][target]
Label isDbNullLabel =il.DefineLabel();
Label finishLabel=il.DefineLabel();//索引为0的参数即reader
il.Emit(OpCodes.Ldarg_0); //stack is now [target][target][reader]
EmitInt32(il, index); //stack is now [target][target][reader][index]
il.Emit(OpCodes.Dup);//stack is now [target][target][reader][index][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.Dup); //stack is now [target][target][value-as-object][value-as-object]
StoreLocal(il, valueCopyLocal);//字段类型
Type colType = reader.GetFieldType(index);//tinyint(1) null//属性/字段类型
Type memberType = item.MemberType;//bool?
if (memberType == typeof(char) || memberType == typeof(char?))
{
il.EmitCall(OpCodes.Call,typeof(SqlMapper).GetMethod(
memberType== typeof(char) ? nameof(SqlMapper.ReadChar) : nameof(SqlMapper.ReadNullableChar), BindingFlags.Static | BindingFlags.Public), null); //stack is now [target][target][typed-value]
}else{
il.Emit(OpCodes.Dup);//stack is now [target][target][value][value]
il.Emit(OpCodes.Isinst, typeof(DBNull)); //stack is now [target][target][value-as-object][DBNull or null]//跳转到marklable
il.Emit(OpCodes.Brtrue_S, isDbNullLabel); //stack is now [target][target][value-as-object]//unbox nullable enums as the primitive, i.e. byte etc
var nullUnderlyingType =Nullable.GetUnderlyingType(memberType);var unboxType = nullUnderlyingType?.IsEnum() == true ?nullUnderlyingType : memberType;if(unboxType.IsEnum())
{
Type numericType=Enum.GetUnderlyingType(unboxType);if (colType == typeof(string))
{if (enumDeclareLocal == -1)
{
enumDeclareLocal= il.DeclareLocal(typeof(string)).LocalIndex;
}
il.Emit(OpCodes.Castclass,typeof(string)); //stack is now [target][target][string]
StoreLocal(il, enumDeclareLocal); //stack is now [target][target]
il.Emit(OpCodes.Ldtoken, unboxType); //stack is now [target][target][enum-type-token]
il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)), null);//stack is now [target][target][enum-type]
LoadLocal(il, enumDeclareLocal); //stack is now [target][target][enum-type][string]
il.Emit(OpCodes.Ldc_I4_1); //stack is now [target][target][enum-type][string][true]
il.EmitCall(OpCodes.Call, enumParse, null); //stack is now [target][target][enum-as-object]
il.Emit(OpCodes.Unbox_Any, unboxType); //stack is now [target][target][typed-value]
}else{
FlexibleConvertBoxedFromHeadOfStack(il, colType, unboxType, numericType);
}if (nullUnderlyingType != null)
{
il.Emit(OpCodes.Newobj, memberType.GetConstructor(new[] { nullUnderlyingType })); //stack is now [target][target][typed-value]
}
}else if (memberType.FullName ==LinqBinary)
{
il.Emit(OpCodes.Unbox_Any,typeof(byte[])); //stack is now [target][target][byte-array]
il.Emit(OpCodes.Newobj, memberType.GetConstructor(new Type[] { typeof(byte[]) }));//stack is now [target][target][binary]
}else{
TypeCode dataTypeCode= TypeExtensions.GetTypeCode(colType), unboxTypeCode =TypeExtensions.GetTypeCode(unboxType);boolhasTypeHandler;if ((hasTypeHandler = typeHandlers.ContainsKey(unboxType)) || colType == unboxType || dataTypeCode == unboxTypeCode || dataTypeCode ==TypeExtensions.GetTypeCode(nullUnderlyingType))
{if(hasTypeHandler)
{#pragma warning disable 618il.EmitCall(OpCodes.Call,typeof(TypeHandlerCache<>).MakeGenericType(unboxType).GetMethod(nameof(TypeHandlerCache.Parse)), null); //stack is now [target][target][typed-value]
#pragma warning restore 618}else{
il.Emit(OpCodes.Unbox_Any, unboxType);//stack is now [target][target][typed-value]
}
}else{//not a direct match; need to tweak the unbox
FlexibleConvertBoxedFromHeadOfStack(il, colType, nullUnderlyingType ?? unboxType, null);if (nullUnderlyingType != null)
{
il.Emit(OpCodes.Newobj, unboxType.GetConstructor(new[] { nullUnderlyingType })); //stack is now [target][target][typed-value]
}
}
}
}if (specializedConstructor == null)
{//Store the value in the property/field
if (item.Property != null)
{
il.Emit(type.IsValueType()?OpCodes.Call : OpCodes.Callvirt, DefaultTypeMap.GetPropertySetter(item.Property, type));
}else{
il.Emit(OpCodes.Stfld, item.Field);//stack is now [target]
}
}//跳转到finishLabel
il.Emit(OpCodes.Br_S, finishLabel); //stack is now [target]
il.MarkLabel(isDbNullLabel);//incoming stack: [target][target][value]
if (specializedConstructor != null)
{
il.Emit(OpCodes.Pop);if(item.MemberType.IsValueType())
{int localIndex =il.DeclareLocal(item.MemberType).LocalIndex;
LoadLocalAddress(il, localIndex);
il.Emit(OpCodes.Initobj, item.MemberType);
LoadLocal(il, localIndex);
}else{
il.Emit(OpCodes.Ldnull);
}
}else if (applyNullSetting && (!memberType.IsValueType() || Nullable.GetUnderlyingType(memberType) != null))
{
il.Emit(OpCodes.Pop);//stack is now [target][target]//can load a null with this value
if(memberType.IsValueType())
{//must be Nullable for some T
GetTempLocal(il, ref structLocals, memberType, true); //stack is now [target][target][null]
}else{//regular reference-type
il.Emit(OpCodes.Ldnull); //stack is now [target][target][null]
}//Store the value in the property/field
if (item.Property != null)
{
il.Emit(type.IsValueType()?OpCodes.Call : OpCodes.Callvirt, DefaultTypeMap.GetPropertySetter(item.Property, type));//stack is now [target]
}else{
il.Emit(OpCodes.Stfld, item.Field);//stack is now [target]
}
}else{
il.Emit(OpCodes.Pop);//stack is now [target][target]
il.Emit(OpCodes.Pop); //stack is now [target]
}if (first &&returnNullIfFirstMissing)
{
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldnull);//stack is now [null]
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Br, allDone);
}
il.MarkLabel(finishLabel);
}
first= false;
index++;
}if(type.IsValueType())
{
il.Emit(OpCodes.Pop);
}else{if (specializedConstructor != null)
{
il.Emit(OpCodes.Newobj, specializedConstructor);
}
il.Emit(OpCodes.Stloc_1);//stack is empty
#if !NETSTANDARD1_3
if(supportInitialize)
{
il.Emit(OpCodes.Ldloc_1);
il.EmitCall(OpCodes.Callvirt,typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.EndInit)), null);
}#endif}
il.MarkLabel(allDone);
il.BeginCatchBlock(typeof(InvalidCastException)); //stack is Exception
il.Emit(OpCodes.Ldloc_0); //stack is Exception, index
il.Emit(OpCodes.Ldarg_0); //stack is Exception, index, reader
LoadLocal(il, valueCopyLocal); //stack is Exception, index, reader, value
il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SqlMapper.ThrowDataException)), null);
il.EndExceptionBlock();
il.Emit(OpCodes.Ldloc_1);//stack is [rval]
if(type.IsValueType())
{
il.Emit(OpCodes.Box, type);
}
il.Emit(OpCodes.Ret);var funcType = System.Linq.Expressions.Expression.GetFuncType(typeof(IDataReader), returnType);return (Func)dm.CreateDelegate(funcType);
}