You can create a proxy to work in-between of source list and filtered view.
public class Indexer<T> : IEnumerable<T>
{
public T this[int index]
{
get => All().ElementAt(index);
set
{
var i = 0;
foreach (var item in _source)
if (_filter(item))
{
if (i++ == index)
_source[i] = value;
break;
}
}
}
public IEnumerable<T> All() => _source.Where(o => _filter(o));
readonly IList<T> _source;
readonly Func<T, bool> _filter;
public Indexer(IList<T> source, Func<T, bool> filter)
{
_source = source;
_filter = filter;
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() => All().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => All().GetEnumerator();
}
This proxy will take care to handle indexes and simplify the usage:
List<int> foo = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };
var bar1 = new Indexer<int>(foo, o => o % 2 == 0);
Console.WriteLine(string.Join(",", bar1)); // 2,4,6,8
bar1[0] = -1;
Console.WriteLine(string.Join(",", bar1)); // 4,6,8
Console.WriteLine(string.Join(",", foo)); // 1,-1,3,4,5,6,7,8