Morelinq收购.它有什么作用



我正在检查Jon Skeet的Morelinq,我对收购扩展源代码感到好奇

实现如下

        /// <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;
            }
        }

从我的理解中,它收到了IEnumerable<IDisposable>,并创建了List<IDisposable>

我无法掌握这里可能出错的一切。

任何人都可以向我解释一下,并可能提供一个示例,该扩展名有用?

AddRange的调用在source上迭代。如果出于任何原因遇到一个例外,则将处置以前获得的任何例外。考虑此示例:

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

由于懒惰的评估,分配disposables时,将不例外。但是,当Aquire内的AddRange调用到达第三个元素(尝试打开"doesnotexist.xml")时,将抛出FileNotFoundException。发生这种情况时,Acquire将安全地处理先前的流。简单的ToList/ToArray将使前两个文件流保持打开。

本质上,Acquire可以确保安全打开filenames中的文件,或者没有一个。

假设您有代码创建并返回一次性对象一个:

public IEnumerable<FileStream> GetFiles()
{
    yield return File.OpenRead("file1");
    yield return File.OpenRead("file2"); // does not exist
    yield return File.OpenRead("file3");
}

您需要获取所有一次性对象,但是如果在获取中有一个例外,那么已经产生的对象将保留在记忆中而不会被处置。因此,Acquire要么获取所有流并返回它们,要么在失败后,它处理了所有已经获得的流并重新抛弃异常。

FileStream[] streams = GetFiles().Acquire();

请记住,使用LINQ获得的大多数IEnumerable集合都以懒惰的方式评估,例如您只会得到食谱如何生成列表。仅当您迭代集合时,该代码才能实际执行,在这种情况下,这会发生在disposables.AddRange(source)中。如果此呼叫失败,那么您最终会得到部分应处理的对象集合,这在这里发生:

            foreach (var disposable in disposables)
                disposable.Dispose();

相关内容

  • 没有找到相关文章

最新更新