Linq Func / Expression Local Evaluation

时间:2010-08-06 14:16:30

标签: linq expression-trees

鉴于此代码:

        int min = 0;

        Expression<Func<List<IUser>, bool>> ulContainsJohn = 
                    (l => l.Where(u => u.FirstName == "John").Count() > min);

        Assert.AreEqual(true, ulContainsJohn.Compile()(userList));

        min = 3;

        Assert.AreEqual(true, ulContainsJohn.Compile()(userList));

该列表包含1个“John”,但第二个断言失败。如何热切地将min的值绑定到Func,所以它不会尝试重新评估变量min?

澄清:我不想改变签名。我希望表达式树能够将min作为变量而不是作为常量表达式进行avaluate。是否有转换min的评估,以便树具有常量表达而不是变量评估?

3 个答案:

答案 0 :(得分:1)

你必须把它作为一个参数。

    Expression<Func<List<IUser>, int,  bool>> ulContainsJohn = 
                (List<IUser> l, int min) =>  (l.Where(u => u.FirstName == "John").Count() > min);


    ulContainsJohn.Compile()(userList, min);

答案 1 :(得分:1)

编辑:阅读您的评论,尝试使用函数创建器。

Func<int, Func<List<IUser>, bool>> createFn = (min) =>
    (l) => (l.Count(u => u.FirstName == "John") > min);

Func<List<IUser>, bool>> contains0 = createFn(0);

Assert.AreEqual(true, contains0(userList));

Func<List<IUser>, bool>> contains3 = createFn(3);

Assert.AreEqual(true, contains3(userList));

尝试使用1个元素数组。丑陋,但它确实有效。

var values = new int[] { 0 };

Expression<Func<List<IUser>, bool>> ulContainsJohn = 
                (l => l.Where(u => u.FirstName == "John").Count() > values[0]);

Assert.AreEqual(true, ulContainsJohn.Compile()(userList));

values[0] = 3;

Assert.AreEqual(true, ulContainsJohn.Compile()(userList));

另一种选择,更好:

private int Minimum { get; set; }

...

Expression<Func<List<IUser>, bool>> ulContainsJohn = 
            (l => l.Where(u => u.FirstName == "John").Count() > Minimum);

Func<List<IUser>, bool> fn = ulContainsJohn.Compile();
Assert.AreEqual(true, fn(userList));

Minimum = 3;

Assert.AreEqual(true, fn(userList));

答案 2 :(得分:0)

最简单的解决方案是创建一个单独的变量:

    int min = 0;
    int staticMin = min;
    Func<List<IUser>, bool> ulContainsJohn = 
                l => l.Where(u => u.FirstName == "John").Count() > staticMin ;