Reputation: 42364
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.
Upvotes: 8
Views: 4044
Reputation: 5543
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});
Upvotes: 3
Reputation: 20044
I think icambron is right, IMHO the better readable version is this:
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);
The from join select
statements are for queries, they should not be misused for mutating the contents of a sequence.
EDIT: Here is another link providing some insights why using a functional form of ForEach
is not a good idea.
Upvotes: 5
Reputation: 391346
If the compiler isn't able to infer the correct type to pass to a lambda, you can of course specify the type yourself.
This should work fine:
select
(Foo f2, b) => { f2.MissingProp = b.MissingProp; return f2; }
Note that as you've already noticed, you cannot reuse f
and hope that it will retain its meaning. This is a new method signature, with new parameters, so you need to use a distinct name for it.
When you do, you notice that the compiler isn't able to figure out by itself what type the first argument should be, but you can specify it, like above.
Upvotes: 1
Reputation: 16065
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.
Upvotes: 1