Emit 实体绑定源码开源,支持类以及匿名类绑定(原创)

发布时间 2023-10-20 11:49:45作者: China-Mr-zhong

动态实体绑定 主要有以下两种

1、表达式树构建委托

2、Emit构建委托

根据我的经验 Emit 代码量可以更少可以很好实现代码复用

Emit实践开源项目地址跳转 https://www.cnblogs.com/China-Mr-zhong/p/17514567.html 查看

using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;

namespace Fast.Framework.Extensions
{

    /// <summary>
    /// 可空扩展类
    /// </summary>
    public static class NullableExtensions
    {

        /// <summary>
        /// 到Nullable
        /// </summary>
        private static readonly Dictionary<Type, MethodInfo> toNullableCache;

        /// <summary>
        /// 构造方法
        /// </summary>
        static NullableExtensions()
        {
            toNullableCache = new Dictionary<Type, MethodInfo>()
            {
                { typeof(short),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(short) })},
                { typeof(ushort),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(ushort) })},
                { typeof(int),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(int) })},
                { typeof(uint),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(uint) })},
                { typeof(long),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(long) })},
                { typeof(ulong),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(ulong) })},
                { typeof(float),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(float) })},
                { typeof(double),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(double) })},
                { typeof(decimal),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(decimal) })},
                { typeof(char),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(char) })},
                { typeof(byte),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(byte) })},
                { typeof(sbyte),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(sbyte) })},
                { typeof(bool),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(bool) })},
                { typeof(string),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(string) })},
                { typeof(DateTime),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(DateTime) })},
                { typeof(DateTimeOffset),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(DateTimeOffset) })},
                { typeof(TimeSpan),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(TimeSpan) })},
                { typeof(Guid),typeof(NullableExtensions).GetMethod(nameof(ToNullable), new Type[] { typeof(Guid) })},
            };
        }

        /// <summary>
        /// 获取ToNullable方法信息
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static MethodInfo GetToNullableMethodInfo(this Type type)
        {
            if (!toNullableCache.ContainsKey(type))
            {
                throw new NotSupportedException($"类型:{type.Name}暂不支持转换");
            }
            return toNullableCache[type];
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static short? ToNullable(short value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static ushort? ToNullable(ushort value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static int? ToNullable(int value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static uint? ToNullable(uint value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static long? ToNullable(long value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static ulong? ToNullable(ulong value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static float? ToNullable(float value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static double? ToNullable(double value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static decimal? ToNullable(decimal value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static char? ToNullable(char value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static byte? ToNullable(byte value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static sbyte? ToNullable(sbyte value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool? ToNullable(bool value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static DateTime? ToNullable(DateTime value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static DateTimeOffset? ToNullable(DateTimeOffset value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static TimeSpan? ToNullable(TimeSpan value)
        {
            return value;
        }

        /// <summary>
        /// 到Nullable
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static Guid? ToNullable(Guid value)
        {
            return value;
        }
    }


}
using System;
using System.Text;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using Fast.Framework.Cache;
using System.Data;
using Fast.Framework.Utils;
using System.Text.Json;
using Fast.Framework.Exceptions;
using Fast.Framework.Models;
using System.Reflection.Emit;

namespace Fast.Framework.Extensions
{

    /// <summary>
    /// DbDataReader扩展类
    /// </summary>
    public static class DbDataReaderExtensions
    {
        /// <summary>
        /// 获取方法信息缓存
        /// </summary>
        private static readonly Dictionary<Type, MethodInfo> getMethodInfoCache;

        /// <summary>
        /// 转换方法信息
        /// </summary>
        private static readonly Dictionary<Type, ConvertInfo> convertMethodInfos;

        /// <summary>
        /// 是否DBNull方法信息
        /// </summary>
        private static readonly MethodInfo isDBNullMethodInfo;

        /// <summary>
        /// 是否空或空格字符串方法信息
        /// </summary>
        private static readonly MethodInfo isNullOrWhiteSpaceMethodInfo;

        /// <summary>
        /// Guid到字符串
        /// </summary>
        private static readonly MethodInfo guidToStringMethodInfo;

        /// <summary>
        /// 静态构造方法
        /// </summary>
        static DbDataReaderExtensions()
        {
            var getValueMethod = typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetValue), new Type[] { typeof(int) });

            isDBNullMethodInfo = typeof(IDataRecord).GetMethod(nameof(IDataRecord.IsDBNull), new Type[] { typeof(int) });

            isNullOrWhiteSpaceMethodInfo = typeof(string).GetMethod(nameof(string.IsNullOrWhiteSpace), new Type[] { typeof(string) });

            guidToStringMethodInfo = typeof(Guid).GetMethod(nameof(Guid.ToString), new Type[] { typeof(Guid) });

            getMethodInfoCache = new Dictionary<Type, MethodInfo>()
            {
                { typeof(object),getValueMethod},
                { typeof(short),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetInt16), new Type[] { typeof(int) })},
                { typeof(ushort),getValueMethod},
                { typeof(int),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetInt32), new Type[] { typeof(int) })},
                { typeof(uint),getValueMethod},
                { typeof(long),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetInt64), new Type[] { typeof(int) })},
                { typeof(ulong),getValueMethod},
                { typeof(float),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetFloat), new Type[] { typeof(int) })},
                { typeof(double),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetDouble), new Type[] { typeof(int) })},
                { typeof(decimal),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetDecimal), new Type[] { typeof(int) })},
                { typeof(char),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetChar), new Type[] { typeof(int) })},
                { typeof(byte),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetByte), new Type[] { typeof(int) })},
                { typeof(sbyte),getValueMethod},
                { typeof(bool),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetBoolean),new Type[]{ typeof(int)})},
                { typeof(string),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetString),new Type[]{ typeof(int)})},
                { typeof(DateTime),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetDateTime),new Type[]{ typeof(int)})},
                { typeof(TimeSpan),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetValue),new Type[]{ typeof(int)})},
                { typeof(Guid),typeof(IDataRecord).GetMethod(nameof(IDataRecord.GetGuid),new Type[]{ typeof(int)})}
            };

            convertMethodInfos = new Dictionary<Type, ConvertInfo>()
            {
                { typeof(short),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToInt16)
                }
                },
                { typeof(ushort),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToUInt16)
                }
                },
                { typeof(int),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToInt32)
                }
                },
                { typeof(uint),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToUInt32)
                }
                },
                { typeof(long),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToInt64)
                }
                },
                { typeof(ulong),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToUInt64)
                }
                },
                { typeof(float),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToSingle)
                }
                },
                { typeof(double),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToDouble)
                }
                },
                { typeof(decimal),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToDecimal)
                } },
                { typeof(char),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToChar)
                }
                },
                { typeof(byte),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToByte)
                }
                },
                { typeof(sbyte),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToSByte)
                }
                },
                { typeof(bool),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToBoolean)
                }
                },
                { typeof(string),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToString)
                }
                },
                { typeof(DateTime),new ConvertInfo()
                {
                    TargetType=typeof(Convert),
                    MethodName=nameof(Convert.ToDateTime)
                }
                },
                { typeof(Guid),new ConvertInfo()
                {
                    TargetType=typeof(Guid),
                    MethodName=nameof(Guid.Parse)
                }
                }
            };
        }

        /// <summary>
        /// 快速设置值
        /// </summary>
        /// <param name="il">IL</param>
        /// <param name="dbColumn">数据库列</param>
        /// <param name="type">类型</param>
        /// <param name="type">是否Json</param>
        private static void FastSetValue(ILGenerator il, DbColumn dbColumn, Type type, bool isJson = false)
        {
            var getValueMethodInfo = getMethodInfoCache[dbColumn.DataType];
            var underlyingType = Nullable.GetUnderlyingType(type);
            var isNullable = false;
            if (underlyingType != null)
            {
                isNullable = true;
            }
            else
            {
                underlyingType = type;
            }

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldc_I4, dbColumn.ColumnOrdinal.Value);
            il.Emit(OpCodes.Callvirt, getValueMethodInfo);

            if (isJson)
            {
                if (!getValueMethodInfo.ReturnType.Equals(typeof(string)))
                {
                    throw new FastException($"数据库列{dbColumn.ColumnName}不是字符串类型不支持Json序列化.");
                }
                var ifLabel = il.DefineLabel();
                var endIfLabel = il.DefineLabel();
                il.Emit(OpCodes.Call, isNullOrWhiteSpaceMethodInfo);
                il.Emit(OpCodes.Brtrue_S, ifLabel);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldc_I4, dbColumn.ColumnOrdinal.Value);
                il.Emit(OpCodes.Callvirt, getValueMethodInfo);
                il.Emit(OpCodes.Ldnull);
                var deserializeGenericMethodInfo = typeof(Json).GetMethod(nameof(Json.Deserialize));
                var deserializeMethodInfo = deserializeGenericMethodInfo.MakeGenericMethod(type);
                il.Emit(OpCodes.Call, deserializeMethodInfo);
                il.Emit(OpCodes.Br_S, endIfLabel);
                il.MarkLabel(ifLabel);
                il.Emit(OpCodes.Ldnull);
                il.MarkLabel(endIfLabel);
            }
            else
            {
                var returnType = getValueMethodInfo.ReturnType;
                if (returnType.Equals(typeof(float)) || returnType.Equals(typeof(double)) || returnType.Equals(typeof(decimal)))
                {
                    var v = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Stloc_S, v);
                    il.Emit(OpCodes.Ldloca_S, v);
                    il.Emit(OpCodes.Ldstr, "G0");
                    var converMethodInfo = returnType.GetMethod("ToString", new Type[] { typeof(string) });
                    il.Emit(OpCodes.Call, converMethodInfo);
                    returnType = typeof(string);
                }
                if (!underlyingType.Equals(returnType))//底层类型不等于值类型转换处理
                {
                    if (dbColumn.DataType.Equals(typeof(Guid)) && underlyingType.Equals(typeof(string)))
                    {
                        il.Emit(OpCodes.Callvirt, guidToStringMethodInfo);//Guid转字符串
                    }
                    else
                    {
                        if (!convertMethodInfos.ContainsKey(underlyingType))
                        {
                            throw new NotSupportedException($"{nameof(underlyingType)}暂不支持转换.");
                        }
                        var converInfo = convertMethodInfos[underlyingType];
                        var converMethodInfo = converInfo.TargetType.GetMethod(converInfo.MethodName, new Type[] { returnType });
                        if (converMethodInfo.IsVirtual)
                        {
                            il.Emit(OpCodes.Callvirt, converMethodInfo);
                        }
                        else
                        {
                            il.Emit(OpCodes.Call, converMethodInfo);
                        }
                    }
                }

                if (isNullable)//可空类型转换
                {
                    il.Emit(OpCodes.Call, underlyingType.GetToNullableMethodInfo());
                }
            }
        }

        /// <summary>
        /// 快速设置值
        /// </summary>
        /// <param name="result">结果</param>
        /// <param name="il">IL</param>
        /// <param name="dbColumn">数据库列</param>
        /// <param name="columnInfo">列信息</param>
        private static void FastSetValue(LocalBuilder result, ILGenerator il, DbColumn dbColumn, ColumnInfo columnInfo)
        {
            il.Emit(OpCodes.Ldloc, result);
            FastSetValue(il, dbColumn, columnInfo.MemberType, columnInfo.IsJson);
            if (columnInfo.IsField)
            {
                il.Emit(OpCodes.Stfld, columnInfo.FieldInfo);
            }
            else
            {
                il.Emit(OpCodes.Callvirt, columnInfo.PropertyInfo.SetMethod);
            }
        }

        /// <summary>
        /// 初始化默认值
        /// </summary>
        /// <param name="il">IL</param>
        /// <param name="type">类型</param>
        private static void InitDeafultValue(ILGenerator il, Type type)
        {
            var v = il.DeclareLocal(type);
            il.Emit(OpCodes.Ldloca_S, v);
            il.Emit(OpCodes.Initobj, type);
            il.Emit(OpCodes.Ldloc_S, v);
        }

        /// <summary>
        /// 创建快速设置值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbColumns">数据库列</param>
        /// <returns></returns>
        public static Func<IDataReader, T> CreateFastSetValue<T>(this ReadOnlyCollection<DbColumn> dbColumns)
        {
            var type = typeof(T);
            var keys = dbColumns.Select(s =>
            {
                if (s.AllowDBNull == null)
                {
                    return $"{s.ColumnName}_{s.DataTypeName}_True";
                }
                else
                {
                    return $"{s.ColumnName}_{s.DataTypeName}_{s.AllowDBNull}";
                }
            });

            var cacheKey = $"{nameof(CreateFastSetValue)}_{type.GUID}_{string.Join(",", keys)}";

            return StaticCache<Func<IDataReader, T>>.GetOrAdd(cacheKey, () =>
            {
                var method = new DynamicMethod("FastEntity", type, new Type[] { typeof(IDataReader) }, type, true);
                var il = method.GetILGenerator();
                var result = il.DeclareLocal(type);
                if (type.IsClass())
                {
                    var entityInfo = type.GetEntityInfo();
                    if (entityInfo.IsAnonymousType)
                    {
                        //success
                        foreach (var dbColumn in dbColumns)
                        {
                            var columnInfo = entityInfo.ColumnInfos.FirstOrDefault(f => f.ColumnName == dbColumn.ColumnName);
                            if (columnInfo == null)
                            {
                                InitDeafultValue(il, entityInfo.ColumnInfos[dbColumn.ColumnOrdinal.Value].MemberType);
                            }
                            else
                            {
                                if (dbColumn.AllowDBNull == null || dbColumn.AllowDBNull.Value)
                                {
                                    var ifLabel = il.DefineLabel();
                                    var endIfLabel = il.DefineLabel();
                                    il.Emit(OpCodes.Ldarg_0);
                                    il.Emit(OpCodes.Ldc_I4, dbColumn.ColumnOrdinal.Value);
                                    il.Emit(OpCodes.Callvirt, isDBNullMethodInfo);
                                    il.Emit(OpCodes.Brtrue_S, ifLabel);
                                    FastSetValue(il, dbColumn, columnInfo.MemberType, columnInfo.IsJson);
                                    il.Emit(OpCodes.Br_S, endIfLabel);
                                    il.MarkLabel(ifLabel);
                                    InitDeafultValue(il, columnInfo.MemberType);
                                    il.MarkLabel(endIfLabel);
                                }
                                else
                                {
                                    FastSetValue(il, dbColumn, columnInfo.MemberType, columnInfo.IsJson);
                                }
                            }
                        }
                        var memberTypes = entityInfo.ColumnInfos.Select(s => s.MemberType).ToArray();
                        var constructorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, memberTypes);
                        il.Emit(OpCodes.Newobj, constructorInfo);
                        il.Emit(OpCodes.Stloc, result);
                    }
                    else
                    {
                        //success
                        var constructorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes);
                        il.Emit(OpCodes.Newobj, constructorInfo);
                        il.Emit(OpCodes.Stloc, result);
                        foreach (var dbColumn in dbColumns)
                        {
                            var columnInfo = entityInfo.ColumnInfos.FirstOrDefault(f => f.ColumnName == dbColumn.ColumnName);
                            if (columnInfo != null)
                            {
                                if (!getMethodInfoCache.ContainsKey(dbColumn.DataType))
                                {
                                    throw new NotSupportedException($"数据类型:{dbColumn.DataType}暂不支持绑定.");
                                }
                                if (dbColumn.AllowDBNull == null || dbColumn.AllowDBNull.Value)
                                {
                                    var endIfLabel = il.DefineLabel();
                                    il.Emit(OpCodes.Ldarg_0);
                                    il.Emit(OpCodes.Ldc_I4, dbColumn.ColumnOrdinal.Value);
                                    il.Emit(OpCodes.Callvirt, isDBNullMethodInfo);
                                    il.Emit(OpCodes.Brtrue, endIfLabel);
                                    FastSetValue(result, il, dbColumn, columnInfo);
                                    il.MarkLabel(endIfLabel);
                                }
                                else
                                {
                                    FastSetValue(result, il, dbColumn, columnInfo);
                                }
                            }
                        }
                    }
                    il.Emit(OpCodes.Ldloc, result);
                    il.Emit(OpCodes.Ret);
                }
                else
                {
                    //success
                    if (dbColumns[0].AllowDBNull == null || dbColumns[0].AllowDBNull.Value)
                    {
                        var endIfLabel = il.DefineLabel();
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldc_I4, dbColumns[0].ColumnOrdinal.Value);
                        il.Emit(OpCodes.Callvirt, isDBNullMethodInfo);
                        il.Emit(OpCodes.Brtrue, endIfLabel);
                        FastSetValue(il, dbColumns[0], typeof(T));
                        il.Emit(OpCodes.Stloc, result);
                        il.MarkLabel(endIfLabel);
                    }
                    else
                    {
                        FastSetValue(il, dbColumns[0], typeof(T));
                        il.Emit(OpCodes.Stloc, result);
                    }
                    il.Emit(OpCodes.Ldloc, result);
                    il.Emit(OpCodes.Ret);
                }
                return method.CreateDelegate<Func<IDataReader, T>>();
            });
        }

        /// <summary>
        /// 最终处理
        /// </summary>
        /// <param name="reader">阅读器</param>
        /// <returns></returns>
        private static void FinalProcessing(this DbDataReader reader)
        {
            if (!reader.NextResult())
            {
                reader.Close();
            }
        }

        /// <summary>
        /// 最终处理异步
        /// </summary>
        /// <param name="reader">阅读器</param>
        /// <returns></returns>
        private static async Task FinalProcessingAsync(this DbDataReader reader)
        {
            if (!await reader.NextResultAsync())
            {
                await reader.CloseAsync();
            }
        }

        /// <summary>
        /// 第一构建
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataReader">数据读取</param>
        /// <returns></returns>
        public static T FirstBuild<T>(this DbDataReader dataReader)
        {
            var reader = dataReader;
            var dbColumns = reader.GetColumnSchema();
            T t = default;
            if (reader.Read())
            {
                var func = dbColumns.CreateFastSetValue<T>();
                t = func.Invoke(reader);
            }
            reader.FinalProcessing();
            return t;
        }

        /// <summary>
        /// 第一构建异步
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataReader">数据读取</param>
        /// <returns></returns>
        public static async Task<T> FirstBuildAsync<T>(this Task<DbDataReader> dataReader)
        {
            var reader = await dataReader;
            var dbColumns = await reader.GetColumnSchemaAsync();
            T t = default;
            if (await reader.ReadAsync())
            {
                var func = dbColumns.CreateFastSetValue<T>();
                t = func.Invoke(reader);
            }
            await reader.FinalProcessingAsync();
            return t;
        }

        /// <summary>
        /// 列表构建
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataReader">数据读取</param>
        /// <returns></returns>
        public static List<T> ListBuild<T>(this DbDataReader dataReader)
        {
            var reader = dataReader;
            var dbColumns = reader.GetColumnSchema();
            var list = new List<T>();
            var func = dbColumns.CreateFastSetValue<T>();
            while (reader.Read())
            {
                list.Add(func.Invoke(reader));
            }
            reader.FinalProcessing();
            return list;
        }

        /// <summary>
        /// 列表构建异步
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataReader">数据读取</param>
        /// <returns></returns>
        public static async Task<List<T>> ListBuildAsync<T>(this Task<DbDataReader> dataReader)
        {
            var reader = await dataReader;
            var dbColumns = await reader.GetColumnSchemaAsync();
            var list = new List<T>();
            var func = dbColumns.CreateFastSetValue<T>();
            while (await reader.ReadAsync())
            {
                list.Add(func.Invoke(reader));
            }
            await reader.FinalProcessingAsync();
            return list;
        }

        /// <summary>
        /// 字典构建
        /// </summary>
        /// <param name="dataReader">数据读取</param>
        /// <returns></returns>
        public static Dictionary<string, object> DictionaryBuild(this DbDataReader dataReader)
        {
            var reader = dataReader;
            var data = new Dictionary<string, object>();
            var dbColumns = reader.GetColumnSchema();
            if (dbColumns.Count > 0 && reader.Read())
            {
                data = new Dictionary<string, object>();
                foreach (var c in dbColumns)
                {
                    data.Add(c.ColumnName, reader.IsDBNull(c.ColumnOrdinal.Value) ? null : reader.GetValue(c.ColumnOrdinal.Value));
                }
            }
            reader.FinalProcessing();
            return data;
        }

        /// <summary>
        /// 字典构建异步
        /// </summary>
        /// <param name="dataReader">数据读取</param>
        /// <returns></returns>
        public static async Task<Dictionary<string, object>> DictionaryBuildAsync(this Task<DbDataReader> dataReader)
        {
            var reader = await dataReader;
            var data = new Dictionary<string, object>();
            var dbColumns = await reader.GetColumnSchemaAsync();
            if (dbColumns.Count > 0 && await reader.ReadAsync())
            {
                data = new Dictionary<string, object>();
                foreach (var c in dbColumns)
                {
                    data.Add(c.ColumnName, reader.IsDBNull(c.ColumnOrdinal.Value) ? null : reader.GetValue(c.ColumnOrdinal.Value));
                }
            }
            await reader.FinalProcessingAsync();
            return data;
        }

        /// <summary>
        /// 字典列表构建
        /// </summary>
        /// <param name="dataReader">数据读取</param>
        /// <returns></returns>
        public static List<Dictionary<string, object>> DictionaryListBuild(this DbDataReader dataReader)
        {
            var reader = dataReader;
            var data = new List<Dictionary<string, object>>();
            var dbColumns = reader.GetColumnSchema();
            if (dbColumns.Count > 0)
            {
                while (reader.Read())
                {
                    var keyValues = new Dictionary<string, object>();
                    foreach (var c in dbColumns)
                    {
                        keyValues.Add(c.ColumnName, reader.IsDBNull(c.ColumnOrdinal.Value) ? null : reader.GetValue(c.ColumnOrdinal.Value));
                    }
                    data.Add(keyValues);
                }
            }
            reader.FinalProcessing();
            return data;
        }

        /// <summary>
        /// 字典列表构建异步
        /// </summary>
        /// <param name="dataReader">数据读取</param>
        /// <returns></returns>
        public static async Task<List<Dictionary<string, object>>> DictionaryListBuildAsync(this Task<DbDataReader> dataReader)
        {
            var reader = await dataReader;
            var data = new List<Dictionary<string, object>>();
            var dbColumns = await reader.GetColumnSchemaAsync();
            if (dbColumns.Count > 0)
            {
                while (await reader.ReadAsync())
                {
                    var keyValues = new Dictionary<string, object>();
                    foreach (var c in dbColumns)
                    {
                        keyValues.Add(c.ColumnName, reader.IsDBNull(c.ColumnOrdinal.Value) ? null : reader.GetValue(c.ColumnOrdinal.Value));
                    }
                    data.Add(keyValues);
                }
            }
            await reader.FinalProcessingAsync();
            return data;
        }
    }
}