8

I have a LINQ query that looks like this:

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;
}

I would like to get rid of AddMissingProp and use some form of a lambda in my select clause instead.

I attempted...

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

...but I got the following error:

A local variable named 'f' cannot be declared in this scope because it would give a different meaning to 'f', which is already used in a 'parent or current' scope to denote something else.

How can I "lambda-ize" my query?


Update

This also doesn't work:

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

I get the following error:

The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.

I didn't change the join clause at all, so I'm perplexed.

4

5 回答 5

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语句用于查询,不应误用它们来改变序列的内容。

编辑:这是另一个链接,提供了一些见解,为什么使用函数形式ForEach不是一个好主意。

于 2010-01-07T20:42:07.477 回答
3

You can give types to your parameters in a lambda expression but you need to use different names since you're already using f and b in the query.

(Foo f1, Bar b1) => ...

Edit

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});
于 2010-01-07T20:00:58.760 回答
1

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

于 2010-01-07T20:04:57.413 回答
1

Rewrite this with Lambda syntax.

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

If you need explanation of this syntax, let me know.

于 2010-01-07T20:06:26.383 回答
1

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

这应该可以正常工作:

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

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

当您这样做时,您会注意到编译器无法自行确定第一个参数应该是什么类型,但您可以像上面一样指定它。

于 2010-01-07T21:00:13.013 回答