Возврат первого предмета из нескольких источников с помощью Where() foreach return

Я нашел интересный фрагмент кода, который использует методы Where() и foreach способами, которые не предназначены. Однако их использование представляется очень интересным решением, которое значительно сокращает количество строк кода.

// a, b, c are IEnumerable<string> of any data source and could be expensive to iterate
string GetFirstString(){ foreach( var str in a.Where(...) ) return str; foreach( var str in b.Where(...) ) return str; foreach( var str in c.Where(...) ) return str; return "";
}
</string>

Есть ли лучший способ сделать это так же коротко, но не "злоупотребляет" Where and foreach?

ОБНОВИТЬ:

Это может иметь ошибку, если в каком-либо списке содержится нулевая запись, а предикат Where допускает сквозную нулевую запись, тогда он возвращает null. (В GetFirstString следует ожидать, что в большинстве случаев пропускает нулевые значения)

5 ответов

Попробуй это:

string GetFirstString(){ return a.FirstOrDefault(...) ?? b.FirstOrDefault(...) ?? c.FirstOrDefault(...) ?? "";
}


Вы можете использовать Concat чтобы соединить все с одной последовательностью, затем выберите First.

var list = a.Where(...) .Concat(b.Where(...)) .Concat(c.Where(..)) .Take(1) .ToList();//Make sure we execute the query only once.
if(list.Count > 0) return list[0];
return "";

Примечание. Можно подумать, что Take(1), ToList и возврат первого элемента из списка кажутся излишними, и вы можете изменить его на FirstOrDefault. Но это изменяет семантику кода. Проблема в том, что когда ваша отфильтрованная последовательность содержит значение null, то FirstOrDefault()?? "" FirstOrDefault()?? "" вернет пустую строку, но исходный код OP вернет null вместо этого.


string GetFirstString(){ var str = ""; if( str == null ) str = b.FirstOrDefault(...); if( str == null ) str = b.FirstOrDefault(...); if( str == null ) str = c.FirstOrDefault(...); return str;
}

Это кажется мне уродливым, потому что оно вводит переменную и изменяет всю структуру метода.


Используйте FirstOrDefault() вместо First()

string GetFirstString(){ if (a.Any(...)) return a.FirstOrDefault(...); if (b.Any(...)) return b.FirstOrDefault(...); if (c.Any(...)) return c.FirstOrDefault(...); return ""; }


Вы можете использовать метод расширения Union

string GetFirstString()
{ return a.Where(...) .Union(b.Where(...)) .Union(c.Where(...)).FirstOrDefault();
}

licensed under cc by-sa 3.0 with attribution.