【问题标题】:Creating, combining and caching lambda expressions创建、组合和缓存 lambda 表达式
【发布时间】:2014-05-26 03:30:59
【问题描述】:

假设我有以下内容。

foreach (var loop in helper.Loop(x => x.LoopItems))
{
    loop.Text(x => x.Name);
    loop.Span(x => x.Name);

    foreach (var loopItem in loop.Loop(x => x.NestedLoopItems))
    {
        loopItem.Text(x => x.Age);
    }
}

这仅适用于我当前的实现,但是它必须编译内部 lambda 表达式的次数与循环项的次数一样多。目前,这样做是为了创建表达式以访问List<T> 索引器。例如。 x.ListItems[i]

var methodCallExpression = Expression.Call(_expression, ((PropertyInfo) _expression.Member).PropertyType.GetMethod("get_Item"), Expression.Constant(i));
var expression = Expression.Lambda<Func<TModel, T>>(methodCallExpression, _expression.GetParameter<TModel>());

然后就可以了

var newExpression = CombineExpression(listExpression);
var enumerable = newExpression.Compile().Invoke(_htmlHelper.ViewData.Model);

编译步骤似乎是昂贵的一步。 考虑到它需要为每个循环创建一个新循环,是否有任何方法可以缓存它,这样Expression.Constant(i) 中的i 需要在每次修改表达式时递增。

【问题讨论】:

    标签: c# linq lambda expression


    【解决方案1】:

    我不知道 CombineExpression 是做什么的,但是如果您可以从 Func&lt;TModel, T&gt; 更改为 Func&lt;TModel, int, T&gt;(假设索引器始终是 int),否则您可以向该方法添加另一个泛型,因为您已经在传递“ i" 以获取表达式中的常量。

    也不完全确定 _expression 是什么类型,所以我不知道这是否正是在调用我认为的重载。

    var parameterExpression = Expression.Parameter(typeof(int), "i");
    var methodCallExpression = Expression.Call(_expression, ((PropertyInfo) _expression.Member).PropertyType.GetMethod("get_Item"), parameterExpression);
    var expression = Expression.Lambda<Func<TModel, int, T>>(methodCallExpression, _expression.GetParameter<TModel>(), parameterExpression);
    

    然后您可以编译表达式并获取Func&lt;TModel, int, T&gt;,并且在调用 Func 时您将传入“i”值。

    再一次,因为我不知道 CombineExpression 是做什么的,但是如果你从中得到一个强类型的 Func,你可以在没有调用的情况下调用它。

    另一个说明为什么表达式可以访问列表索引器?如果您不知道它们的类型但需要将对象转换为 IEnumerable(非泛型)并对其进行迭代,为什么不直接使用 IEnumerable 或最差转换?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多