public Func <IDataRecord, T> CreateMapper <T>(IResultMapperCreateContext context, Type type, ColumnInfo[] columns) { var defaultValue = default(T); var parser = context.GetConverter(columns[0].Type, type, type); return(parser == null ? CreateConvertMapper(defaultValue) : CreateConvertMapper(defaultValue, parser)); }
public Func <IDataRecord, T> CreateMapper <T>(IResultMapperCreateContext context, Type type, ColumnInfo[] columns) { var entries = CreateMapEntries(context, type, columns); var holder = CreateHolder(entries); var holderType = holder.GetType(); var ci = type.GetConstructor(Type.EmptyTypes); if (ci is null) { throw new ArgumentException($"Default constructor not found. type=[{type.FullName}]", nameof(type)); } var dynamicMethod = new DynamicMethod(string.Empty, type, new[] { holderType, typeof(IDataRecord) }, true); var ilGenerator = dynamicMethod.GetILGenerator(); ilGenerator.Emit(OpCodes.Newobj, ci); foreach (var entry in entries) { ilGenerator.Emit(OpCodes.Dup); ilGenerator.Emit(OpCodes.Ldarg_1); ilGenerator.EmitLdcI4(entry.Index); if (entry.Converter == null) { var method = getValueMethod.MakeGenericMethod(entry.Property.PropertyType); ilGenerator.Emit(OpCodes.Call, method); } else { var field = holderType.GetField($"parser{entry.Index}"); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldfld, field); var method = getValueWithConvertMethod.MakeGenericMethod(entry.Property.PropertyType); ilGenerator.Emit(OpCodes.Call, method); } ilGenerator.Emit(OpCodes.Callvirt, entry.Property.SetMethod); } ilGenerator.Emit(OpCodes.Ret); var funcType = typeof(Func <,>).MakeGenericType(typeof(IDataRecord), type); return((Func <IDataRecord, T>)dynamicMethod.CreateDelegate(funcType, holder)); }
private static MapEntry[] CreateMapEntries(IResultMapperCreateContext context, Type type, ColumnInfo[] columns) { var selector = (IPropertySelector)context.ServiceProvider.GetService(typeof(IPropertySelector)); var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public) .Where(IsTargetProperty) .ToArray(); var list = new List <MapEntry>(); for (var i = 0; i < columns.Length; i++) { var column = columns[i]; var pi = selector.SelectProperty(properties, column.Name); if (pi == null) { continue; } list.Add(new MapEntry(i, pi, context.GetConverter(column.Type, pi.PropertyType, pi))); } return(list.ToArray()); }
public Func <IDataRecord, T> CreateMapper <T>(IResultMapperCreateContext context, MethodInfo mi, ColumnInfo[] columns) { var type = typeof(T); var selector = (IMappingSelector)context.ServiceProvider.GetService(typeof(IMappingSelector)); var typeMap = selector.Select(mi, type, columns); var converters = typeMap.Constructor.Parameters .Select(x => new { x.Index, Converter = context.GetConverter(columns[x.Index].Type, x.Info.ParameterType, x.Info) }) .Concat(typeMap.Properties .Select(x => new { x.Index, Converter = context.GetConverter(columns[x.Index].Type, x.Info.PropertyType, x.Info) })) .Where(x => x.Converter != null) .ToDictionary(x => x.Index, x => x.Converter); var holder = CreateHolder(converters); var holderType = holder.GetType(); var dynamicMethod = new DynamicMethod(string.Empty, type, new[] { holderType, typeof(IDataRecord) }, true); var ilGenerator = dynamicMethod.GetILGenerator(); // Variables var objectLocal = converters.Count > 0 ? ilGenerator.DeclareLocal(typeof(object)) : null; var valueTypeLocals = ilGenerator.DeclareValueTypeLocals( typeMap.Constructor.Parameters.Select(x => x.Info.ParameterType) .Concat(typeMap.Properties.Select(x => x.Info.PropertyType))); var isShort = valueTypeLocals.Count + (objectLocal != null ? 1 : 0) <= 256; // -------------------------------------------------------------------------------- // Constructor // -------------------------------------------------------------------------------- foreach (var parameterMap in typeMap.Constructor.Parameters) { var hasValueLabel = ilGenerator.DefineLabel(); var next = ilGenerator.DefineLabel(); // Stack ilGenerator.EmitStackColumnValue(parameterMap.Index); ilGenerator.EmitCheckDbNull(); ilGenerator.Emit(OpCodes.Brfalse_S, hasValueLabel); // Null ilGenerator.Emit(OpCodes.Pop); ilGenerator.EmitStackDefault(parameterMap.Info.ParameterType, valueTypeLocals, isShort); ilGenerator.Emit(OpCodes.Br_S, next); // Value ilGenerator.MarkLabel(hasValueLabel); if (converters.ContainsKey(parameterMap.Index)) { ilGenerator.EmitConvertByField(holderType.GetField($"parser{parameterMap.Index}"), objectLocal, isShort); } ilGenerator.EmitTypeConversion(parameterMap.Info.ParameterType); // Next ilGenerator.MarkLabel(next); } // New ilGenerator.Emit(OpCodes.Newobj, typeMap.Constructor.Info); // -------------------------------------------------------------------------------- // Property // -------------------------------------------------------------------------------- foreach (var propertyMap in typeMap.Properties) { var hasValueLabel = ilGenerator.DefineLabel(); var next = ilGenerator.DefineLabel(); ilGenerator.Emit(OpCodes.Dup); // Stack ilGenerator.EmitStackColumnValue(propertyMap.Index); ilGenerator.EmitCheckDbNull(); ilGenerator.Emit(OpCodes.Brfalse_S, hasValueLabel); // Null ilGenerator.Emit(OpCodes.Pop); ilGenerator.EmitStackDefault(propertyMap.Info.PropertyType, valueTypeLocals, isShort); ilGenerator.Emit(OpCodes.Br_S, next); // Value ilGenerator.MarkLabel(hasValueLabel); if (converters.ContainsKey(propertyMap.Index)) { ilGenerator.EmitConvertByField(holderType.GetField($"parser{propertyMap.Index}"), objectLocal, isShort); } ilGenerator.EmitTypeConversion(propertyMap.Info.PropertyType); // Next ilGenerator.MarkLabel(next); // Set ilGenerator.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, propertyMap.Info.SetMethod); } ilGenerator.Emit(OpCodes.Ret); return((Func <IDataRecord, T>)dynamicMethod.CreateDelegate(typeof(Func <IDataRecord, T>), holder)); }
public Func <IDataRecord, T> CreateMapper <T>(IResultMapperCreateContext context, Type type, ColumnInfo[] columns) { // TODO var entries = CreateMapEntries(context, type, columns); var holder = CreateHolder(entries); var holderType = holder.GetType(); var ci = type.GetConstructor(Type.EmptyTypes); if (ci is null) { throw new ArgumentException($"Default constructor not found. type=[{type.FullName}]", nameof(type)); } var getValue = typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetValue)); var dynamicMethod = new DynamicMethod(string.Empty, type, new[] { holderType, typeof(IDataRecord) }, true); var ilGenerator = dynamicMethod.GetILGenerator(); ilGenerator.Emit(OpCodes.Newobj, ci); foreach (var entry in entries) { // TODO // GetValue // isnull // class // struct init // value // class // basic // nullable // other? exp? var hasValueLabel = ilGenerator.DefineLabel(); var setPropertyLabel = ilGenerator.DefineLabel(); ilGenerator.Emit(OpCodes.Dup); // [T][T] ilGenerator.Emit(OpCodes.Ldarg_1); // [T][T][IDataRecord] ilGenerator.EmitLdcI4(entry.Index); // [T][T][IDataRecord][index] ilGenerator.Emit(OpCodes.Callvirt, getValue); // [T][T][Value] ilGenerator.Emit(OpCodes.Callvirt, entry.Property.SetMethod); //if (entry.Converter == null) //{ // var method = getValueMethod.MakeGenericMethod(entry.Property.PropertyType); // ilGenerator.Emit(OpCodes.Call, method); //} //else //{ // var field = holderType.GetField($"parser{entry.Index}"); // ilGenerator.Emit(OpCodes.Ldarg_0); // ilGenerator.Emit(OpCodes.Ldfld, field); // var method = getValueWithConvertMethod.MakeGenericMethod(entry.Property.PropertyType); // ilGenerator.Emit(OpCodes.Call, method); //} } // TODO ValueType ? ilGenerator.Emit(OpCodes.Ret); var funcType = typeof(Func <,>).MakeGenericType(typeof(IDataRecord), type); return((Func <IDataRecord, T>)dynamicMethod.CreateDelegate(funcType, holder)); //var entries = CreateMapEntries(context, type, columns); //var holder = CreateHolder(entries); //var holderType = holder.GetType(); //var ci = type.GetConstructor(Type.EmptyTypes); //if (ci is null) //{ // throw new ArgumentException($"Default constructor not found. type=[{type.FullName}]", nameof(type)); //} //var dynamicMethod = new DynamicMethod(string.Empty, type, new[] { holderType, typeof(IDataRecord) }, true); //var ilGenerator = dynamicMethod.GetILGenerator(); //ilGenerator.Emit(OpCodes.Newobj, ci); //foreach (var entry in entries) //{ // ilGenerator.Emit(OpCodes.Dup); // ilGenerator.Emit(OpCodes.Ldarg_1); // ilGenerator.EmitLdcI4(entry.Index); // if (entry.Converter == null) // { // var method = getValueMethod.MakeGenericMethod(entry.Property.PropertyType); // ilGenerator.Emit(OpCodes.Call, method); // } // else // { // var field = holderType.GetField($"parser{entry.Index}"); // ilGenerator.Emit(OpCodes.Ldarg_0); // ilGenerator.Emit(OpCodes.Ldfld, field); // var method = getValueWithConvertMethod.MakeGenericMethod(entry.Property.PropertyType); // ilGenerator.Emit(OpCodes.Call, method); // } // ilGenerator.Emit(OpCodes.Callvirt, entry.Property.SetMethod); //} //ilGenerator.Emit(OpCodes.Ret); //var funcType = typeof(Func<,>).MakeGenericType(typeof(IDataRecord), type); //return (Func<IDataRecord, T>)dynamicMethod.CreateDelegate(funcType, holder); }