这个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>();
}
}
}
答案 0 :(得分:2)
此解决方案不会删除我假设您尝试通过调用“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();
}
这个解决方案确实使用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();