Reputation: 16290
Currently, to replace an item I'm using the following code:
var oldItem = myList.Single(x => x.Id == newItem.Id);
var pos = myList.ToList().IndexOf(oldItem);
myList.Remove(oldItem);
myList.ToList().Insert(pos, newItem);
So, I created an extension to do the same as above but using lambda expression, and I came up with this:
public static ICollection<T> Replace<T>(this IEnumerable<T> list, T oldValue, T newValue) where T : class
{
if (list == null)
throw new ArgumentNullException(nameof(list));
return list.Select(x => list.ToList().IndexOf(oldValue) != -1 ? newValue : x).ToList();
}
So I can use it as follows:
var oldItem = myList.Single(x => x.Id == newItem.Id);
myList = myList.Replace(oldItem, newItem);
However, it's not working. What am I missing?
Upvotes: 1
Views: 3894
Reputation: 74530
While you can't replace the item in the materialized collection itself, you can replace the item that is yielded from a different IEnumerable<T>
at a certain position.
All you have to do is use the Select
extension method on IEnumerable<T>
to map to the new item when the Id
property matches, and use the new IEnumerable<T>
instance, like so:
// Assuming newItem is already defined, has the value you want to yield
// and T is the type of newItem
IEnumerable<T> newEnumerable = myList.Select(i =>
i.Id == newItem.Id ? newItem : i
);
Then, when you iterate through the newEnumerable
, when the item in the old list has an Id
equal to newItem.Id
, it will yield newItem
.
Upvotes: 7
Reputation: 1030
IEnumerable
is for traversing a generic data structure. Think about it as read-only access. In fact, making modifications to the IEnumerable
while enumerating it is a big NO NO. Your original solution is fine, except for the last line. Just do Remove and Insert.
Upvotes: 0