C# 使用表达式树指定泛型类属性

C# 使用表达式树指定泛型类属性,c#,generics,expression-trees,C#,Generics,Expression Trees,救命啊,我似乎有点迷路了 昨天问了一个问题后,我决定看看表情树。我找到了一个很好的小地方开始,以下是我到目前为止所做的: // Gets the property type ParameterExpression paramProperty = Expression.Parameter(property.PropertyType); // Gets the value from row[0] (SqlDataReader) ParameterExpression paramVal

救命啊,我似乎有点迷路了

昨天问了一个问题后,我决定看看表情树。我找到了一个很好的小地方开始,以下是我到目前为止所做的:

  // Gets the property type
  ParameterExpression paramProperty = Expression.Parameter(property.PropertyType);
  // Gets the value from row[0] (SqlDataReader)
  ParameterExpression paramValue = Expression.Parameter(row[0].GetType());
  // really no clue, makes a property so to speak?
  MemberExpression prop = Expression.Property(paramProperty, property);
  // assigns the property the value from the SqlDataReader
  BinaryExpression assign = Expression.Assign(prop, paramValue);
  // adds to an expression list ready for compilation
  exps.Add(assign);
  // allows things to be executed sequentially?
  BlockExpression blockExpression = exps.Count > 0 ? Expression.Block(exps) : Expression.Block(Expression.Empty());
  // create the parameter array
  List<ParameterExpression> paramArr = new List<ParameterExpression>();
  paramArr.Add(paramProperty);
  paramArr.Add(paramValue);
  // get a lambda so I can compile this for re-use
  Expression<Action<T>> lamExp = Expression.Lambda<Action<T>>(blockExpression, paramArr);
//获取属性类型
ParameterExpression paramProperty=Expression.Parameter(property.PropertyType);
//从第[0]行(SqlDataReader)获取值
ParameterExpression paramValue=Expression.Parameter(行[0].GetType());
//真的没有线索,可以这么说是财产吗?
MemberExpression prop=Expression.Property(paramProperty,Property);
//将SqlDataReader中的值指定给属性
BinaryExpression assign=表达式.assign(prop,paramValue);
//添加到准备编译的表达式列表中
exps.添加(分配);
//允许按顺序执行事情?
BlockExpression BlockExpression=exps.Count>0?Expression.Block(exps):Expression.Block(Expression.Empty());
//创建参数数组
List paramArr=新列表();
paramArr.Add(paramProperty);
paramArr.Add(paramValue);
//获取一个lambda,这样我就可以编译它以供重用
表达式lamExp=Expression.Lambda(blockExpression,paramArr);
首先,我的评论正确吗?我用一个教程和msdn文档的老方法拼凑这些信息

从我一直在读的内容来看,我认为我应该能够编译它,将它存储在一个以类型为键的字典中,并在需要时调用它。例如

  ConcurrentDictionary<Type, ??> ExpressionCache;
  if(ExpressionCache.ContainsKey(typeof(T))
  {
         // property is the variable of a foreach loop of type PropertyInfo
         ExpressionCache[typeof(T)](property); 
  } // else do the first piece of code...
ConcurrentDictionary表达式缓存;
if(ExpressionCache.ContainsKey(typeof(T))
{
//属性是PropertyInfo类型的foreach循环的变量
ExpressionCache[typeof(T)](属性);
}//否则请执行第一段代码。。。
所以总而言之,

  • 我走对了吗
  • 我对这些表达的评论正确吗
  • 我应该使用什么类型的并发字典
  • 缓存引用时,如何将不同的参数传递给lambda

  • 只要能很好地解释,任何改进或建议都是受欢迎的。我试图理解它是如何工作的,而不仅仅是为了让它工作:)

    听起来你在寻找评论,而不是其他任何东西……对吗

    首先,您将如何在编译时使用SqlReader

    // Gets the value from row[0] (SqlDataReader)
    ParameterExpression paramValue = Expression.Parameter(Type.GetTypeFromHandle(row[0].GetType()));
    
    你的lambda需要两个参数,所以有些地方出了问题(操作需要一个参数)

    我想你真正想要的是一个
    Func
    。这样,您将SqlDataReader提供给它,它将生成一个T。因此:

    var list = new List<T>();
    // get a SqlDataReader
    while (reader.Read())
    {
        Func<SqlDataReader, T> readRow = GetReader<T>();
        list.Add(readRow(reader);
    }
    
    var list=newlist();
    //获取SqlDataReader
    while(reader.Read())
    {
    Func readRow=GetReader();
    list.Add(readRow(reader));
    }
    
    我会将你的缓存存储为

     ConcurrentDictionary<Type, Delegate> ExpressionCache;  // can't use T here since each Func will have a different T
    
    ConcurrentDictionary ExpressionCache;//无法在此处使用t,因为每个Func将具有不同的t
    
    然后在检索时将其强制转换为调用方的适当委托类型(让您的方法采用泛型参数:

     public Func<SqlDataReader, T> GetReader<T>() 
     { 
         Delegate d;
         if(!ExpressionCache.TryGetValue(typeof(T), out d)
         {
             ExpressionCache[typeof(T)] = d = // build and compile lambda
         } 
         // cast to strong typed delegate...we don't want to have to DynamicInvoke...that's slow
         return (Func<SqlDataReader, T>)d;
     }
    
    public Func GetReader()
    { 
    d代表;
    如果(!ExpressionCache.TryGetValue)(类型(T),输出d)
    {
    ExpressionCache[typeof(T)]=d=//构建并编译lambda
    } 
    //强制转换为强类型委托…我们不希望必须使用DynamicVoke…这太慢了
    返回(Func)d;
    }
    
    因此…对于lambda生成器/编译器:

            // hang on to row[string] property 
            var indexerProperty = typeof(SqlDataReader).GetProperty("Item", new[] { typeof(string) });
    
            // list of statements in our dynamic method
            var statements = new List<Expression>();
    
            // store instance for setting of properties
            ParameterExpression instanceParameter = Expression.Variable(typeof(T));
            ParameterExpression sqlDataReaderParameter = Expression.Parameter(typeof(SqlDataReader));
    
            // create and assign new T to variable: var instance = new T();
            BinaryExpression createInstance = Expression.Assign(instanceParameter, Expression.New(typeof(T)));
            statements.Add(createInstance);
    
            foreach (var property in typeof(T).GetProperties())
            {
                // instance.MyProperty
                MemberExpression getProperty = Expression.Property(instanceParameter, property);
    
                // row[property] -- NOTE: this assumes column names are the same as PropertyInfo names on T
                IndexExpression readValue = Expression.MakeIndex(sqlDataReaderParameter, indexerProperty, new[] { Expression.Constant(property.Name) });
    
                // instance.MyProperty = row[property]
                BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
    
                statements.Add(assignProperty);
            }
    
            var returnStatement = instanceParameter;
            statements.Add(returnStatement);
    
            var body = Expression.Block(instanceParameter.Type, new[] { instanceParameter }, statements.ToArray());
    
            /* so we end up with
             * T Read(SqlDataReader row)
             * {
             * var x = new T();
             * x.Prop1 = (cast)row["Prop1"]
             * x.Prop2 = (cast)row["Prop2"]
             * x.Prop3 = (cast)row["Prop3"]
             * x.Prop4 = (cast)row["Prop4"]
             * etc.
             * return x
             * }
             */
            var lambda = Expression.Lambda<Func<SqlDataReader, T>>(body, sqlDataReaderParameter);
    
            // cache me!
            return lambda.Compile();
    
    //保留行[string]属性
    var indexerProperty=typeof(SqlDataReader).GetProperty(“Item”,new[]{typeof(string)});
    //动态方法中的语句列表
    var语句=新列表();
    //用于设置属性的存储实例
    ParameterExpression instanceParameter=Expression.Variable(typeof(T));
    ParameterExpression sqlDataReaderParameter=Expression.Parameter(typeof(SqlDataReader));
    //创建新的T并将其分配给变量:var instance=new T();
    BinaryExpression createInstance=Expression.Assign(instanceParameter,Expression.New(typeof(T));
    添加(createInstance);
    foreach(typeof(T).GetProperties()中的var属性)
    {
    //instance.MyProperty
    MemberExpression getProperty=Expression.Property(instanceParameter,Property);
    //行[property]--注意:这假设列名与T上的PropertyInfo名称相同
    IndexExpression readValue=Expression.MakeIndex(sqlDataReaderParameter,indexerProperty,new[]{Expression.Constant(property.Name)});
    //instance.MyProperty=行[属性]
    BinaryExpression assignProperty=Expression.Assign(getProperty,Expression.Convert(readValue,property.PropertyType));
    增加(转让财产);
    }
    var returnStatement=instanceParameter;
    报表。添加(返回报表);
    var body=Expression.Block(instanceParameter.Type,new[]{instanceParameter},statements.ToArray());
    /*因此,我们以
    *T读取(SqlDataReader行)
    * {
    *var x=新的T();
    *x.Prop1=(强制转换)行[“Prop1”]
    *x.Prop2=(强制转换)行[“Prop2”]
    *x.Prop3=(强制转换)行[“Prop3”]
    *x.Prop4=(强制转换)行[“Prop4”]
    *等等。
    *返回x
    * }
    */
    var lambda=Expression.lambda(主体,sqlDataReaderParameter);
    //缓存我!
    返回lambda.Compile();
    
    还没有测试过,所以请小心使用,自己试试


    我不确定您的预期用途是否正确……是吗?

    既然您已经有了类型,为什么还要调用Type.GetTypeFromHandle?@JeffN825,嘘,您没有看到;)你能总结一下你正在构建的表达式应该做什么吗?@Jeff Mercado,基本上与链接问题中的相同,只是一个表达式树版本。我从未使用过表达式树,所以我想学习。有任何资源或代码挑战(如try and)