Использование условного оператора в лямбда-выражении в ForEach () в общем списке? - PullRequest
10 голосов
/ 30 ноября 2009

Разрешено ли иметь условный оператор в лямбда-выражении в 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 += "");

Ошибка компиляции -> «Только операторы присваивания, вызова, приращения, декремента и новых выражений объекта могут использоваться в качестве оператора»

Попытка использовать обычный, если тоже не работает:

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

Просто не возможно?

Ответы [ 4 ]

29 голосов
/ 30 ноября 2009

Вы используете более короткую форму лямбда-выражений, которые допускают только одно выражение.
Вам нужна длинная форма, которая допускает несколько операторов.

Например:

items.ForEach(item => {
    if (item.Contains("I Care About")) 
        whatICareAbout += item + ", ";
});
5 голосов
/ 30 ноября 2009

Что вы пытаетесь достичь? Вы пытаетесь сформировать строку элементов, разделенных запятыми, где они содержат определенное значение? В 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 - отличный способ убедиться в отсутствии трейлинга ","

4 голосов
/ 30 ноября 2009

Проблема была в том, что выражение

item.Contains("I Care About") ? whatICareAbout += item + "," : whatICareAbout += ""

не является заявлением . Он просто возвращает значение типа string.

Есть способ заставить его работать (просто для удовольствия):

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

Я просто добавил вызов метода .GetType() для создания оператора из исходного выражения, и он скомпилирован.

1 голос
/ 30 ноября 2009

Попробуйте скобки:

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

+ = имеет более высокий приоритет, чем?, Возможно, поэтому вы получаете ошибку. С круглыми скобками ошибка может исчезнуть. Не уверен на 100% в этом, хотя ... лямбда-выражения могут иметь дополнительные ограничения, препятствующие использованию операторов присваивания.

ОБНОВЛЕНИЕ:

Вместо нескольких операторов + = гораздо удобнее поместить условное выражение в правую часть присваивания, например:

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

Но я думаю, что ответ @ 1017 * Мэтта Брекона выше (который я только что увидел, когда собирался опубликовать это) даже лучше, чем мой пример, поскольку он касается удаления терминала ",". Посмотри на его ответ ...: -)

...