使用LinqKit构建的## Lambda Expression无法编译

时间:2010-04-21 22:07:34

标签: c# linq lambda compilation

这个lambda不编译,但我不明白为什么。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using LinqKit;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
    {
        var barModel = new BarModel();
        string id = "some";

        Console.WriteLine(barModel.subFor(id).ToString());
            // output: m => (True AndAlso (m.key == value(ConsoleApplication2.Bar`1+<>c__DisplayClass0[ConsoleApplication2.Model]).id))
        Console.ReadKey();


        var subworkitems = barModel.list.Where(barModel.subFor(id).Compile());
                // Exception {"variable 'm' of type 'ConsoleApplication2.Model' referenced from scope '', but it is not defined"}

        Console.WriteLine(subworkitems.ToString());
        Console.ReadKey();
    }
}

class Bar<TModel>
{

    public Bar(Expression<Func<TModel, string>> foreignKeyExpression)
    {
        _foreignKeyExpression = foreignKeyExpression;
    }

    private Expression<Func<TModel, string>> _foreignKeyExpression { get; set; }

    public Expression<Func<TModel, bool>> subFor(string id)
    {

        var ex = forTargetId(id);

        return ex;
    }

    public Expression<Func<TModel, bool>> forTargetId(String id)
    {

        var fc = _foreignKeyExpression;

        Expression<Func<TModel, bool>> predicate = m => true;

        var result = predicate.And(m => fc.Invoke(m) == id).Expand();

        return result;

    }

}

class Model
{
    public string key;
    public string value;
}

class BarModel : Bar<Model>
{
    public List<Model> list;

    public BarModel() : base(m => m.key) 
    {
        list = new List<Model>();
    }
}


}

1 个答案:

答案 0 :(得分:2)

解决方案1 ​​

此解决方案不会删除我假设您尝试通过调用“Expand”来执行的调用语句。

将“forTargetId(String id)”的结果更改为

predicate.And(m => fc.Invoke(m) == id);

当表达式在where子句中编译时,它将知道它需要将“m”传递给上面的fc表达式。

我改变时的第一个提示

predicate.And(m => fc.Invoke(m) == id).Expand();

predicate.And(n => fc.Invoke(n) == id).Expand();

我可以看到n根本没有被传递。

我通过操作Main方法测试了这个变化,如下所示

static void Main(string[] args)
{
    var barModel = new BarModel();
    barModel.list.Add(new Model() { key = "1", value = "One" });
    barModel.list.Add(new Model() { key = "2", value = "Two" });
    barModel.list.Add(new Model() { key = "some", value = "Three" });

    string id = "some";

    Console.WriteLine(barModel.subFor(id).ToString());
    // output: m => (True AndAlso (m.key == value(ConsoleApplication2.Bar`1+<>c__DisplayClass0[ConsoleApplication2.Model]).id))
    Console.ReadKey();


    var subworkitems = barModel.list.Where(barModel.subFor(id).Compile());
    // Exception {"variable 'm' of type 'ConsoleApplication2.Model' referenced from scope '', but it is not defined"}

    foreach (var si in subworkitems)
    {
        Console.WriteLine(si.key);
        Console.WriteLine(si.value);
    }

    Console.WriteLine(subworkitems.ToString());
    Console.ReadKey();
}

解决方案2

这个解决方案确实使用Expand方法删除了Invoke语句,但是改变了你将语句放在一起的方式。

“扩展”功能在LinqKit网站上公布如下。

Expression<Func<Purchase, bool>> criteria1 = p => p.Price > 1000;
Expression<Func<Purchase, bool>> criteria2 = p => criteria1.Invoke(p) || p.Description.Contains("a");
Console.WriteLine(criteria2.Expand().ToString());
// p => ((p.Price > 1000) || p.Description.Contains("a"))

请注意,他们没有使用“And”方法将这些内容放在一起,而是将这些调用“菊花链”在一起。

而不是

Expression<Func<TModel, bool>> predicate = m => true;
var result = predicate.And(m => fc.Invoke(m) == id).Expand();

这样做

Expression<Func<TModel, bool>> predicate = m => fc.Invoke(m) == id && true;
return predicate.Expand();