LINQ:如何强制基于值的引用?

时间:2010-11-30 22:36:52

标签: c# .net linq

我想提供一组过滤器供用户选择,每个过滤器都对应一个Expression<Func<X, bool>>。所以,我可能想要获取可用项目的动态列表('Joe','Steve','Pete'等),并根据这些名称创建一组“硬编码”过滤器,并让用户选择他想要使用哪个过滤器。我的问题是,即使我尝试根据动态列表中的字符串值“硬编码”我的表达式,表达式仍然将值存储为,看起来是什么,一个悬挂在匿名类型上的属性(和我不知道如何序列化anon。类型)。对不起,如果这令人困惑,我不太清楚如何表达这一点。

这是我的示例代码:

    public class Foo
    {
        public string Name { get; set; }
    }
    static void Main(string[] args)
    {
        Foo[] source = new Foo[]
            {
                new Foo() { Name = "Steven" } ,
                new Foo() { Name = "John" } ,
                new Foo() { Name = "Pete" },
            };

            List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>();
            foreach (Foo f in source)
            {
                Expression<Func<Foo, bool>> exp = x => x.Name == f.Name;
                filterLst.Add(exp);
            }
    }
}

我的问题是,当我看到表情的正文时,它的内容如下:

(x.Name = value(ConsoleApplication1.Program+<>c__DisplayClass3).value)

当我真正想要的是第一个阅读时:

(x.Name = "Steven")

(如果我将我的代码改为此代替,那就是我得到的:

      Expression<Func<Foo, bool>> exp = x => x.Name == "Steven";

我已经尝试将我的值强制转换为本地字符串值,然后将其粘贴到Expression中,但它似乎没有帮助:

    List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>();
    foreach (Foo f in source)
    {
        string value = f.Name;
        Expression<Func<Foo, bool>> exp = x => x.Name == value;
        filterLst.Add(exp);
    }

我不明白为什么(或者甚至是如何)它仍在查看某些匿名类型,即使我使用的是声明为字符串的局部变量。有没有办法按照我的意愿来完成这项工作?

2 个答案:

答案 0 :(得分:7)

anon-type实际上是用于执行变量 capture 的编译器生成类型。使用委托,您可以通过手动实现捕获来解决这个问题,但不能将lambda表达式编译为表达式树。

两种选择:

  • 通过Expression.Constant等
  • 在代码上明确地构建表达式树
  • 学习如何处理匿名类型

后者实际上并不太糟糕;它们通常只是MemberExpression,虽然我有一些代码在全面详细介绍。我还可以提供构建表达式树的示例,但我现在不在PC上,它不适合iPod打字......

简要读到的问题,我会看第一个选项而不是第二个选项。

哦,小心;问题中的第一个 foreach代码看起来容易受到臭名昭着的l值捕获问题的影响;)


编辑:我找到了一台电脑; p

        var param = Expression.Parameter(typeof(Foo), "x");
        var body = Expression.Equal(
            Expression.PropertyOrField(param, "Name"),
            Expression.Constant(f.Name, typeof(string)));

        var exp = Expression.Lambda<Func<Foo, bool>>(body, param);
        filterLst.Add(exp);

答案 1 :(得分:4)

Marc Gravell的回答是正确的,以下是你如何实现他的第一选择:

var filters = 
    from f in source
    let param = Expression.Parameter(typeof(Foo),"x")
    select Expression.Lambda<Func<Foo, bool>>(
        Expression.Equal(
            Expression.Property(param, "Name"),
            Expression.Constant(f.Name)), param);

但这通常不是必需的。你的第二个for循环示例应该适用于所有主要的LINQ提供程序。你需要表达式来使用常量吗?