Поэтому я ударился головой о стену и придумал действительно простое решение для конкретной проблемы замены: найти, удалить, а затем добавить.
var existing = collection.FirstOrDefault(predicate);
if (existing != null)
{
collection.Remove(existing);
collection.Add(newReference);
}
Тем не менее, я рассматриваю это скорее как обходной путь к моей проблеме foreach
, и поэтому разместил этот вопрос как продолжение: Извлечь элемент из коллекции по ссылке в foreach
EDIT:
Для комментария Дэниела А. Уайта:
Обработка только первого была тем, что я намеревался сделать, но это может быть легко изменено, чтобы заменить все:
var existing = collection.Where(predicate);
foreach(var element in existing)
{
collection.Remove(element);
}
for(int i = 0; i < existing.Count); ++i)
{
collection.Add(newReference);
}
Что касается заказа - ICollection
не обязательно заказывается. Таким образом, для исправления этого можно было бы создать новый метод с менее общей подписью
static void ReplaceReference<T>(
IList<T> list,
T newReference,
Func<T, bool> predicate)
, который будет использовать индексатор для замены значений
for(int i = 0; i < list.Count; ++i)
{
if(predicate(list[i]))
{
list[i] = newReference;
// break here if replace-one variant.
}
}
И теперь в основном методе мы проверяем, является ли наша коллекция IList, поэтому упорядоченным, и передаем его в упорядоченную версию:
if(collection is IList<T> list)
{
ReplaceReference(list, newReference, predicate);
return;
}
=============================================== ============================
Sidenote: конечно, есть также подход dumbo:
var newCollection = new List<T>();
foreach(var element in collection)
{
newList.Add(predicate(element) ? newReference : element);
}
collection.Clear();
foreach(var newElement in newCollection)
{
collection.Add(newElement);
}
но это крайне неэффективно.