如何在Linq表达式中使用Expression.MakeIndex?

时间:2013-02-15 08:12:26

标签: c# .net linq expression

属性索引器数组

尝试动态生成以下lambda表达式:

Expression<Func<Program, string>> y = _ => _.x[0];

其中x的类型为List

尝试使用Expression.MakeIndex,但它似乎反弹异常:

Expression.MakeIndex(parameter, typeof (Program).GetProperty("x"), new[] {Expression.Constant(0)})

异常消息:

  

为方法调用提供的参数数量不正确   'System.Collections.Generic.List`1 [System.String] get_x()'

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:5)

这里有两个操作:

  1. x
  2. 获取parameter
  3. 访问索引0的项目
  4. 您需要为此创建两个单独的表达式:

    var property = Expression.Property(parameter, typeof (Program).GetProperty("x"));
    var itemAtPosition0 = Expression.MakeIndex(property, typeof(List<string>).GetProperty("Item"),
                         new [] { Expression.Constant(0) });
    

    "Item"是指索引器属性的默认名称。有关此名称以及如何可靠地检测实际名称的更多信息,请查看this answer

答案 1 :(得分:3)

这个答案假定Program类的定义如下:

public class ProgramZ
{
    public List<string> x { get; set; }
}

问题是您正在尝试将索引应用于Program.x属性,当它确实应该应用于List<string>的索引器属性(称为Item)时

最后,为了能够调用表达式,你需要将它包装成lambda。

以下是执行此操作的代码:

var expr =
    Expression.Lambda<Func<Program, string>>(
        Expression.MakeIndex(
                Expression.Property(
                    parameter,
                    typeof(Program).GetProperty("x")),
                typeof(List<string>).GetProperty("Item"),
                new[] { Expression.Constant(0) }),
        parameter);

以下是调用表达式的方法:

var instance = new ProgramZ { x = new List<string> { "a", "b" } };

Console.WriteLine(expr.Compile().Invoke(instance));

此代码将按预期输出a