用C#/ LINQ中的匿名方法替换常规方法

时间:2010-01-07 19:56:56

标签: c# linq lambda anonymous-methods

我有一个LINQ查询,如下所示:

public IEnumerable<Foo> SelectFooBars()
{
    return
        from
            f in foos
        join
            b in bars
            on f.BarId equals b.Id
        select
            AddMissingProp(f, b.MissingProp);
}

public void AddMissingProp(Foo foo, string missingProp) // substitute this with inline lambda
{
    foo.MissingProp = missingProp;
    return foo;
}

我想摆脱AddMissingProp并在我的select子句中使用某种形式的lambda。

我试图......

...
select
    (f, b) => { f.MissingProp = b.MissingProp; return f }

...但我收到以下错误:

  

名为'f'的局部变量不能在此范围内声明,因为它会给'f'赋予不同的含义,'f'已在'父或当前'范围内用于表示其他内容。

我如何“lambda-ize”我的查询?


更新

这也不起作用:

...
select
    () => { f.MissingProp = b.MissingProp; return f }

我收到以下错误:

  

join子句中某个表达式的类型不正确。调用“加入”时类型推断失败。

我根本没有改变join条款,所以我很困惑。

5 个答案:

答案 0 :(得分:5)

我认为 icambron 是对的,恕我直言,更好的可读版本是这样的:

  var fooBar = from 
                 f in foos
               join 
                 b in bars
                 on f.BarId equals b.Id 
               select new {f,b};

   foreach(var x in fooBar)
        x.f.MissingProp = x.b.MissingProp;

   // EDIT due to comments: add this if you 
   // need IEnumerable<Foo> returned
   return fooBar.Select(fb => fb.f);

from join select语句用于查询,不应该误用它们来改变序列的内容。

编辑:这是另一个link提供了一些见解为什么使用ForEach的功能形式不是一个好主意。

答案 1 :(得分:3)

您可以在lambda表达式中为参数指定类型,但由于您已经在查询中使用了f和b,因此需要使用不同的名称。

(Foo f1,Bar b1)=&gt; ...

修改

return
(
    from 
        f in foos 
    join
        b in bars 
        on f.BarId equals b.Id 
    select 
        new {f, b}
).select(foobar => {foobar.f.BarId = foobar.b.Id; return foobar.f});

答案 2 :(得分:1)

选择     (f2,b2)=&gt; {f2.MissingProp = b2.MissingProp;返回f2}

答案 3 :(得分:1)

使用Lambda语法重写此内容。

var vf2 = foos.Join(bars, f => f.id, b => b.id, (foo, bar) => { foo.MissingProp = bar.MissingProp; return foo; });

如果您需要解释此语法,请与我们联系。

答案 4 :(得分:1)

如果编译器无法推断传递给lambda的正确类型,您当然可以自己指定类型。

这应该可以正常工作:

select
    (Foo f2, b) => { f2.MissingProp = b.MissingProp; return f2; }

请注意,正如您已经注意到的那样,您无法重用f并希望它能保留其含义。这是一个新方法签名,带有新参数,因此您需要为其使用不同的名称。

当你这样做时,你会注意到编译器不能自己弄清楚第一个参数应该是什么类型,但你可以像上面那样指定它。