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