Поскольку никто другой не предоставил его, вот мой метод расширения / enumerable, который реализует RemoveFirst (Predicate match).Суть в том, что вам нужно определить свой собственный IEnumerable для правильного отслеживания состояния - я не смог найти простой способ обойти это.
Вы можете попробовать это в .NET Fiddle здесь.
public static IEnumerable<T> RemoveFirst<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
return new RemoveFirstEnumerable<T>(list, predicate);
}
public static IEnumerable<T> RemoveFirst<T>(this IEnumerable<T> list, T item)
{
return RemoveFirst(list, x => Object.Equals(x, item));
}
private class RemoveFirstEnumerable<T> : IEnumerable<T>
{
IEnumerable<T> m_Source;
Func<T, bool> m_Predicate;
public RemoveFirstEnumerable(IEnumerable<T> source, Func<T, bool> predicate)
{
m_Source = source;
m_Predicate = predicate;
}
public IEnumerator<T> GetEnumerator()
{
return new RemoveFirstEnumerator(m_Source, m_Predicate);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new RemoveFirstEnumerator(m_Source, m_Predicate);
}
private class RemoveFirstEnumerator : IEnumerator<T>
{
IEnumerator<T> m_Enumerator;
Func<T, bool> m_Predicate;
bool m_RemovedOnce = false;
public RemoveFirstEnumerator(IEnumerable<T> source, Func<T, bool> predicate)
{
m_Enumerator = source.Where(WherePredicate).GetEnumerator();
m_Predicate = predicate;
}
bool WherePredicate(T current)
{
// terse version:
return m_RemovedOnce || !(m_RemovedOnce = m_Predicate(current));
// Long version
//if (m_RemovedOnce)
//{
// return true;
//}
//else
//{
// m_RemovedOnce = Object.Equals(x, item);
// return !m_RemovedOnce;
//}
}
public T Current
{
get { return m_Enumerator.Current; }
}
public bool MoveNext()
{
return m_Enumerator.MoveNext();
}
public void Reset()
{
m_Enumerator.Reset();
}
public void Dispose()
{
m_Enumerator.Dispose();
}
object IEnumerator.Current
{
get { return m_Enumerator.Current; }
}
}
}