创建,组合和缓存lambda表达式

时间:2014-05-26 03:31:00

标签: c# linq lambda expression

说我有以下内容。

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);

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

1 个答案:

答案 0 :(得分:1)

我不知道CombineExpression的功能,但是如果你可以从Func<TModel, T>更改为Func<TModel, int, T>(假设索引器总是一个int),那么你可以在这个方法中添加另一个泛型你已经过去了&#34;我&#34;获取表达式中的常量。

也不完全确定_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<TModel, int, T>,并且在调用Func时你会传入&#34; i&#34;值。

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

另一方面注意为什么表达式可以访问列表索引器?为什么不使用IEnumerable&lt;&gt;如果你不知道他们输入但是需要将对象强制转换为IEnumerable(非泛型)并迭代它,那么还是最差的演员?