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());
        }
Пример #4
0
        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));
        }
Пример #5
0
        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);
        }