Возврат первого предмета из нескольких источников с помощью 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.