在泛型列表的ForEach()中使用lambda表达式中的条件运算符?

13
在ForEach中的lambda表达式中使用条件运算符是否允许?
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 += "");

编译错误 -> "仅允许使用赋值、调用、增量、减量和新对象表达式作为语句"

尝试使用普通的if也不起作用:

// :(
items.ForEach(item => if (item.Contains("I Care About")) {whatICareAbout += item + ", ";}

不可能吗?


2
哇,我对这些答案印象非常深刻,都是在几分钟内回答的 :) 我认为@SLaks回答了我的问题意图,但Aggregate()让我大开眼界!:) 再次感谢大家 :) - Jamezor
1
你在条件运算符的类型中使用了一个字符串表达式,并且你需要为你的.ForEach()方法提供一个语句。这就是为什么编译错误会出现的原因。 - Roman Boiko
1
@Roman - 我明白了!我认为 ? x: y 是 if (a) {x} else {y} 的简写,但 ? 返回 x 和 y 的值,这在这种情况下是一个字符串... - Jamezor
4个回答

37

您正在使用lambda表达式的简短形式,该形式只允许一个表达式。
您需要使用长形式,以允许多个语句。

例如:

items.ForEach(item => {
    if (item.Contains("I Care About")) 
        whatICareAbout += item + ", ";
});

6
你想要实现什么?你想要形成一个由逗号分隔的字符串,其中包含特定值的项吗?在Linq中,你可以通过以下方式实现:
 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);

这个输出是 "我关心的项目,我关心的项目,我关心的项目"。

注意:Aggregate是确保没有尾随“,”的好方法。


使用Aggregate进行字符串拼接是一个非常巧妙的想法,我之前从未想过。你可以很容易地将其改为使用StringBuilder,因为StringBuilder具有流畅的接口。 - SLaks
哈哈,我刚刚在我的初始答案中添加了一个Aggregate()代码示例......但是我喜欢你的更好。+1! - Justin Grant

4
问题在于这个表达式。
item.Contains("I Care About") ? whatICareAbout += item + "," : whatICareAbout += ""

is not a statement. 它只返回一个类型为 string 的值。

有一个有趣的技巧可以让它工作:

    items.ForEach(item => (item.Contains("I Care About") ?
    whatICareAbout += item + "," : whatICareAbout += "").GetType());

我只是在初始表达式中添加了调用 .GetType() 方法的语句,然后它就编译通过了。


而对于 .ForEach(),你需要一个语句 :) - Roman Boiko

1

试试括号:

items.ForEach(item => item.Contains("I Care About") ? (whatICareAbout += item + ",") : (whatICareAbout += "") );

+=比?的优先级高,这可能是你得到错误的原因。用括号可以消除这种错误。虽然不100%确定...... lambda表达式可能有额外的限制,防止使用赋值语句。

更新:

与其使用多个+=语句,不如将条件放在赋值语句的右侧,像这样:

List<string> items = new List<string> { "one", "two", "three" };
string whatICareAbout = "";
items.ForEach(item => whatICareAbout +=  item.Contains("I Care About") ? (item + ",") : ""); 

更新2:

但是最好使用Aggregate(),因为它专门为这种情况设计。以下是一个示例:

string whatICareAbout = items.Aggregate("", (total, item) => item.Contains("I Care About") ? (total + item + ",") : total);

但是我认为@Matt Breckon上面的答案(我刚看到,正要发布这篇文章)比我的例子更好,因为它处理了删除终端“,”。看看他的答案... :-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接