zoukankan      html  css  js  c++  java
  • .Net Expression表达式目录树(自己动态创建表达式目录树)

    一直以来自己从数据库取数据,都是遍历SqlDataReader。通过SqlDataReader的string索引器获取数据。

    后来自己研究反射,可以动态的将SqlDataReader的数据赋值给泛型T。省了不少收写代码的工作。但是随着业务量的增加,一直使用反射就会有性能和资源的损耗。为了解决这个问题。就想到了缓存+反射+表达式目录树。把已经赋值过的泛型T,缓存起来,下次找缓存,如果有赋值过具体T类型,就直接取缓存的目录树,然后Compile().Invoke()。这就解决了性能损耗和代码量的问题。

    这个是以前的方法,避免不了性能损耗问题

    public List<T> FindAll<T>() where T : BaseModel
    {
    Type type = typeof(T);
    List<T> list = new List<T>();
    //var Parameter = new SqlParameter("@Id", Id);
    using (SqlConnection connection = new SqlConnection(StaticField.Connection))
    {
    SqlCommand command = new SqlCommand(Cache<T>.DeleteSql, connection);
    //command.Parameters.Add(Parameter);
    connection.Open();
    SqlDataReader reader = command.ExecuteReader();
    while (reader.Read())
    {
    var t = Activator.CreateInstance(type) as T;
    foreach (var item in type.GetProperties())
    {
    item.SetValue(item.Name, reader[$"{item.Name }"]==DBNull.Value?null: reader[$"{item.Name }"]);
    }
    list.Add(t);
    }
    connection.Close();
    return list;
    }
    }

    先解释一下什么是表达式目录树,其实就是把表达式理解成一个树。组装的时候,一个叶一个叶的取组装。拆解的时候一个一个的拆。(从右往左拆或者组装)就比如说表达式

    x.name==5&&x.Age>3。可以拆成x/、name、&&、 x 、age 。这些具体的元素都能找到表达式目录树里面对应的表示方法。具体的方法你们可以研究一下Expression类。里面有方法、属性、字段等等的组装方法。拿上面那个做个例子:

     ParameterExpression parameter = Expression.Parameter(typeof(具体类型), "P");这个P就是给这个委托给起了个别名(统一了一个名字)

    x.name这个name是个属性。所以就添加p的name属性

    PropertyInfo Info = typeof(具体类型).GetProperty("name");
    MemberExpression member = Expression.Property(parameter, Info);//把p和name拼起来就成了p.name.
    表达式目录树里面有表示==、&&、>、乘除等等等。反正都能拼接起来。很多方法,我研究了很长时间,才研究了几个方法。你们自己探究

    这个是使用表达式目录树的方式。自己在添加一个缓存,把已经通过目录树赋值过的缓存起来,下次来的时候,直接用。审了不少性能问题

    public TOut ExpressionConvertToModel<TOut>(SqlDataReader tin)
    {
    ParameterExpression parameter = Expression.Parameter(typeof(SqlDataReader), "P");
    List<MemberBinding> list = new List<MemberBinding>();
    foreach (var item in typeof(TOut).GetProperties())
    {
    string Info = tin[item.Name].ToString();
    if (Info != null)
    {

    //PropertyInfo Infos = tin.GetType().GetProperty("item_get");索引器就是调用对象属性的item_get方法。
    var In = tin.GetType().GetProperties().Where(m => m.GetIndexParameters().Length > 0).ToArray()[1];//获取string索引器
    //MemberExpression member = Expression.Property(parameter, In);//p.属性名
    //下一步就是拼接这个SqlDataReader[]
    var methodCall = Expression.Call(parameter,In.GetMethod, Expression.Constant(item.Name));//call就是调用方法,都一个是p然后是p.Get_item()这个表示索引器的get方法,最后一个是参数

    MethodInfo containsMethod = typeof(object).GetMethod("ToString");
    if (typeof(string) == item.PropertyType)
    {
    containsMethod = typeof(object).GetMethod("ToString");//using System.Reflection;ToString方法
    }
    else if (typeof(bool) == item.PropertyType)
    {
    //下面自己去扩展
    }
    else if (typeof(byte) == item.PropertyType)
    {

    }
    else if (typeof(char) == item.PropertyType)
    {

    }
    else if (typeof(decimal) == item.PropertyType)
    {

    }
    else if (typeof(double) == item.PropertyType)
    {

    }
    else if (typeof(float) == item.PropertyType)
    {

    }
    else if (typeof(long) == item.PropertyType)
    {

    }
    else if (typeof(sbyte) == item.PropertyType)
    {

    }
    else if (typeof(short) == item.PropertyType)
    {

    }
    else if (typeof(uint) == item.PropertyType)
    {

    }
    containsMethod = typeof(object).GetMethod("ToString");//T获取object的Tostring方法
    var methodCal2 = Expression.Call(methodCall, containsMethod);//调用Tostring方法
    //var methodCal2 = Expression.ArrayIndex(methodCall, Expression.Constant(item.Name));
    //var methodCall = Expression.Call(parameter,In.GetMethod ?? throw new InvalidOperationException(), Expression.Constant(item.Name));
    MemberBinding member1 = Expression.Bind(item, methodCal2);//p.属性名=属性名
    list.Add(member1);
    }
    }
    MemberInitExpression memberInit = Expression.MemberInit(Expression.New(typeof(TOut)), list.ToArray());
    Expression<Func<SqlDataReader, TOut>> expression = Expression.Lambda<Func<SqlDataReader, TOut>>(memberInit, new ParameterExpression[] { parameter });
    return expression.Compile().Invoke(tin);
    }

    本文来自博客园,作者:小换哥,转载请注明原文链接:https://www.cnblogs.com/haunge/p/13396400.html

  • 相关阅读:
    MySQL查询缓存
    MySQL复制相关参数详解
    MySQL复制机制
    MySQL数据库的多表查询操作
    MySQL数据库单表查询基本操作及DML语句
    Hadoop大数据系列汇总
    MySQL数据库之日志功能详解
    MySQL数据库扫盲
    MySQL数据库之数据类型及基本使用详解
    MySQL数据库之日志管理
  • 原文地址:https://www.cnblogs.com/haunge/p/13396400.html
Copyright © 2011-2022 走看看