// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace System.Linq { public static partial class EnumerableEx { /// /// Creates a sequence that corresponds to the source sequence, concatenating it with the sequence resulting from /// calling an exception handler function in case of an error. /// /// Source sequence element type. /// Exception type to catch. /// Source sequence. /// Handler to invoke when an exception of the specified type occurs. /// Source sequence, concatenated with an exception handler result sequence in case of an error. public static IEnumerable Catch(this IEnumerable source, Func> handler) where TException : Exception { if (source == null) throw new ArgumentNullException(nameof(source)); if (handler == null) throw new ArgumentNullException(nameof(handler)); return source.Catch_(handler); } /// /// Creates a sequence by concatenating source sequences until a source sequence completes successfully. /// /// Source sequence element type. /// Source sequences. /// Sequence that continues to concatenate source sequences while errors occur. public static IEnumerable Catch(this IEnumerable> sources) { if (sources == null) throw new ArgumentNullException(nameof(sources)); return sources.Catch_(); } /// /// Creates a sequence by concatenating source sequences until a source sequence completes successfully. /// /// Source sequence element type. /// Source sequences. /// Sequence that continues to concatenate source sequences while errors occur. public static IEnumerable Catch(params IEnumerable[] sources) { if (sources == null) throw new ArgumentNullException(nameof(sources)); return sources.Catch_(); } /// /// Creates a sequence that returns the elements of the first sequence, switching to the second in case of an error. /// /// Source sequence element type. /// First sequence. /// Second sequence, concatenated to the result in case the first sequence completes exceptionally. /// The first sequence, followed by the second sequence in case an error is produced. public static IEnumerable Catch(this IEnumerable first, IEnumerable second) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); return new[] {first, second}.Catch_(); } private static IEnumerable Catch_(this IEnumerable source, Func> handler) where TException : Exception { var err = default(IEnumerable); using (var e = source.GetEnumerator()) { while (true) { var c = default(TSource); try { if (!e.MoveNext()) break; c = e.Current; } catch (TException ex) { err = handler(ex); break; } yield return c; } } if (err != null) { foreach (var item in err) yield return item; } } private static IEnumerable Catch_(this IEnumerable> sources) { var error = default(Exception); foreach (var source in sources) { using (var e = source.GetEnumerator()) { error = null; while (true) { var c = default(TSource); try { if (!e.MoveNext()) break; c = e.Current; } catch (Exception ex) { error = ex; break; } yield return c; } if (error == null) break; } } if (error != null) throw error; } } }