-
Notifications
You must be signed in to change notification settings - Fork 418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add private method ToDisposableLinkedList to replace DisposableGroup and Acquire #724
Comments
A first step is to use the |
This is just an idea but public static TCollection Acquire<TSource, TCollection>(this IEnumerable<TSource> source,
TCollection disposables)
where TSource : IDisposable
where TCollection : ICollection<TSource>
{
if (source == null) throw new ArgumentNullException(nameof(source));
try
{
foreach (var disposable in source)
disposables.Add(disposable);
return disposables;
}
catch
{
foreach (var disposable in disposables)
disposable.Dispose();
throw;
}
} And if you have a sealed class DisposableCollection<T> : ICollection<T>, IDisposable
where T : IDisposable
{
readonly LinkedList<T> _disposables = new LinkedList<T>();
public void Dispose()
{
foreach (var disposable in this)
disposable.Dispose();
Clear();
}
public int Count => _disposables.Count;
public bool IsReadOnly => false;
public void Add(T item) => _disposables.AddLast(item);
public void Clear() => _disposables.Clear();
public bool Contains(T item) => _disposables.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => _disposables.CopyTo(array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _disposables.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public bool Remove(T item) => _disposables.Remove(item);
} then it can also be used with |
As explained here, And with this behavior, the code below will throw (it doesn't in #726): var sequenceA = Enumerable.Range(1, 1);
var sequenceB = new BreakingSequence<int>();
sequenceA.Interleave(sequenceB).Take(1).Consume(); Is it acceptable ? |
Transpose
,Interleave
andSortedMerge
are three methods that have to deals with enumeration of a collection ofIEnumerable
.In this three methods, implementation have to ensure that all enumerators from the input enumerables are disposed when:
1. is assured by
Acquire
in the three methods.2. is assured by
DisposableGroup
inSortedMerge
and by sometry {} finaly {}
blocks inTranspose
andInterleave
(and those makeAcquire
useless as discussed here #696 ).Acquire
return an array,DisposableGroup
is based on an list.For the three methods we can build cases where enumerators are heavily removed from the array/list (or, for
Transpose
, tested as null).Since remove for array/list (or repeatedly skip null elements) is O(N) in time, that lead to O(N²) time complexity.
This can be easily fixed with the use of a
LinkedList
(and by removing null elements from it).I propose a
ToDisposableLinkedList()
method that 1. have the functionality of Acquire (on error, dispose already acquired elements) and provide aDisposableLinkedList
that 2. have the functionality ofDisposableGroup<T>
(being disposable and dispose its content when disposed).It will be used like that:
The
using
here allow to remove thetry {} finally {}
from here:MoreLINQ/MoreLinq/Transpose.cs
Lines 92 to 96 in 9fc8486
and here:
MoreLINQ/MoreLinq/Interleave.cs
Lines 141 to 146 in 9fc8486
and improve the
DisposableGroup/Acquire
combo from here:MoreLINQ/MoreLinq/SortedMerge.cs
Line 101 in 9fc8486
The text was updated successfully, but these errors were encountered: