Using conditional operator in lambda expression in ForEach() on a generic List?
Solution 1
You're using the shorter form of lambda expressions, which only allow a single expressions.
You need to the long form, which allows multiple statements.
For example:
items.ForEach(item => {
if (item.Contains("I Care About"))
whatICareAbout += item + ", ";
});
Solution 2
What are you trying to acheive? Are you trying to form a string of comma separated items where they contain a particular value? In linq you would achieve this using the following:
List<string> items = new List<string> { "Item 1", "Item 2", "Item I Care About", "Item I Care About", "Item I Care About" };
string whatICareAbout = items.Where(x => x.Contains("I Care About"))
.Aggregate( (y, z) => y + ", " + z);
The output from this is "Item I Care About, Item I Care About, Item I Care About".
Note: Aggregate is a great way of ensuring there is no trailing ","
Solution 3
The problem was that expression
item.Contains("I Care About") ? whatICareAbout += item + "," : whatICareAbout += ""
is not a statement. It just returns a value which has type string
.
There is a trick to make it work (just for fun):
items.ForEach(item => (item.Contains("I Care About") ?
whatICareAbout += item + "," : whatICareAbout += "").GetType());
I simply added call to .GetType()
method to create a statement from initial expression, and it compiled.
Solution 4
Try parentheses:
items.ForEach(item => item.Contains("I Care About") ? (whatICareAbout += item + ",") : (whatICareAbout += "") );
+= has a higher precedence than ?, that may be why you're getting the error. With parentheses, the error may go away. Not 100% sure of this, though... lambda expressions may have additional restrictions which prevent use of assignment statements.
UPDATE:
Instead of multiple += statements, it's a lot cleaner to put the conditional on the right-hand side of the assignment, like this:
List<string> items = new List<string> { "one", "two", "three" };
string whatICareAbout = "";
items.ForEach(item => whatICareAbout += item.Contains("I Care About") ? (item + ",") : "");
UPDATE 2:
But it's even better to just use Aggregate() since it's designed for exactly this scenario. Here's one sample:
string whatICareAbout = items.Aggregate("", (total, item) => item.Contains("I Care About") ? (total + item + ",") : total);
But I think @Matt Breckon's answer above (that I just saw as I was about to post this)is even better than my example since it deals with removing the terminal ",". Look at his answer... :-)
Jamezor
Updated on July 09, 2022Comments
-
Jamezor almost 2 years
Is it not allowed to have a conditional operator in a lambda expression in ForEach?
List<string> items = new List<string>{"Item 1", "Item 2", "Item I Care About"}; string whatICareAbout = ""; // doesn't compile :( items.ForEach(item => item.Contains("I Care About") ? whatICareAbout += item + "," : whatICareAbout += "");
Compilation error -> "Only assignment, call, increment, decrement, and new object expressions can be used as a statement"
Trying to use a normal if doesn't work either:
// :( items.ForEach(item => if (item.Contains("I Care About")) {whatICareAbout += item + ", ";}
Just not possible?
-
SLaks over 14 yearsUsing
Aggregate
for sting concat is a very neat idea which I haven't thought of. You could easily change it to use aStringBuilder
becauseStringBuilder
has a fluent interface. -
Justin Grant over 14 yearshah, I was just adding an Aggregate() code sample to my initial answer... but I like yours better. +1 !
-
Roman Boiko over 14 yearsAnd for
.ForEach()
you needed a statement :)