Using conditional operator in lambda expression in ForEach() on a generic List?

筅森魡賤 提交于 2019-12-04 18:17:31

问题


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?


回答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 + ", ";
});



回答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 ","




回答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.




回答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... :-)



来源:https://stackoverflow.com/questions/1816859/using-conditional-operator-in-lambda-expression-in-foreach-on-a-generic-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!