MoreLinq Acquire. What does it do?

c#, morelinq

Solution

The call to `AddRange` iterates over `source`. If for any reason it encounters an exception, any that had previously been acquired will be disposed. Consider this example:

var filenames = new[] { "file1.xml", "file2.xml", "doesnotexist.xml" };
var disposables = filenames.Select(fn => File.OpenRead(fn));
var fileStreams = disposables.Acquire();

No exception will be thrown when you're assigning `disposables`, because of lazy evaluation. However, when the call to `AddRange` inside `Aquire` reaches the third element (where it tries to open `"doesnotexist.xml"`), a `FileNotFoundException` will be thrown. When this happens, `Acquire` will safely dispose the previous streams. A simple `ToList` / `ToArray` would leave the first two file streams open.

In essence, `Acquire` is there to ensure that either all the files in `filenames` is safely opened, or none of them are.

Problem

I was inspecting the Jon Skeet's MoreLinq and I became curious about the acquire extension source code The implementation is as follows ``` /// <summary> /// Ensures that a source sequence of <see cref="IDisposable"/> /// objects are all acquired successfully. If the acquisition of any /// one <see cref="IDisposable"/> fails then those successfully /// acquired till that point are disposed. /// </summary> /// <typeparam name="TSource">Type of elements in <paramref name="source"/> sequence.</typeparam> /// <param name="source">Source sequence of <see cref="IDisposable"/> objects.</param> /// <returns> /// Returns an array of all the acquired <see cref="IDisposable"/> /// object and in source order. /// </returns> /// <remarks> /// This operator executes immediately. /// </remarks> public static TSource[] Acquire<TSource>(this IEnumerable<TSource> source) where TSource : IDisposable { if (source == null) throw new ArgumentNullException("source"); var disposables = new List<TSource>(); try { disposables.AddRange(source); return disposables.ToArray(); } catch { foreach (var disposable in disposables) disposable.Dispose(); throw; } } ``` From my understanding it receives a `IEnumerable<IDisposable>` and it creates a `List<IDisposable>`. I can't grasp whatever can go wrong here. Can anyone explain it to me, and possibly provide an example where this extension can be useful?

Original source