// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
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("source");
if (handler == null)
throw new ArgumentNullException("handler");
return source.Catch_(handler);
}
private static IEnumerable Catch_(this IEnumerable source, Func> handler)
where TException : Exception
{
var err = default(IEnumerable);
using (var e = source.GetEnumerator())
{
while (true)
{
var b = default(bool);
var c = default(TSource);
try
{
b = e.MoveNext();
c = e.Current;
}
catch (TException ex)
{
err = handler(ex);
break;
}
if (!b)
break;
yield return c;
}
}
if (err != null)
{
foreach (var item in err)
yield return item;
}
}
///
/// 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("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("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("first");
if (second == null)
throw new ArgumentNullException("second");
return new[] { first, second }.Catch_();
}
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 b = default(bool);
var c = default(TSource);
try
{
b = e.MoveNext();
c = e.Current;
}
catch (Exception ex)
{
error = ex;
break;
}
if (!b)
break;
yield return c;
}
if (error == null)
break;
}
}
if (error != null)
throw error;
}
///
/// Creates a sequence whose termination or disposal of an enumerator causes a finally action to be executed.
///
/// Source sequence element type.
/// Source sequence.
/// Action to run upon termination of the sequence, or when an enumerator is disposed.
/// Source sequence with guarantees on the invocation of the finally action.
public static IEnumerable Finally(this IEnumerable source, Action finallyAction)
{
if (source == null)
throw new ArgumentNullException("source");
if (finallyAction == null)
throw new ArgumentNullException("finallyAction");
return source.Finally_(finallyAction);
}
private static IEnumerable Finally_(this IEnumerable source, Action finallyAction)
{
try
{
foreach (var item in source)
yield return item;
}
finally
{
finallyAction();
}
}
///
/// Creates a sequence that concatenates both given sequences, regardless of whether an error occurs.
///
/// Source sequence element type.
/// First sequence.
/// Second sequence.
/// Sequence concatenating the elements of both sequences, ignoring errors.
public static IEnumerable OnErrorResumeNext(this IEnumerable first, IEnumerable second)
{
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
return OnErrorResumeNext_(new[] { first, second });
}
///
/// Creates a sequence that concatenates the given sequences, regardless of whether an error occurs in any of the sequences.
///
/// Source sequence element type.
/// Source sequences.
/// Sequence concatenating the elements of the given sequences, ignoring errors.
public static IEnumerable OnErrorResumeNext(params IEnumerable[] sources)
{
if (sources == null)
throw new ArgumentNullException("sources");
return OnErrorResumeNext_(sources);
}
///
/// Creates a sequence that concatenates the given sequences, regardless of whether an error occurs in any of the sequences.
///
/// Source sequence element type.
/// Source sequences.
/// Sequence concatenating the elements of the given sequences, ignoring errors.
public static IEnumerable OnErrorResumeNext(this IEnumerable> sources)
{
if (sources == null)
throw new ArgumentNullException("sources");
return OnErrorResumeNext_(sources);
}
private static IEnumerable OnErrorResumeNext_(IEnumerable> sources)
{
foreach (var source in sources)
{
using (var innerEnumerator = source.GetEnumerator())
{
while (true)
{
var value = default(TSource);
try
{
if (!innerEnumerator.MoveNext())
break;
value = innerEnumerator.Current;
}
catch
{
break;
}
yield return value;
}
}
}
}
///
/// Creates a sequence that retries enumerating the source sequence as long as an error occurs.
///
/// Source sequence element type.
/// Source sequence.
/// Sequence concatenating the results of the source sequence as long as an error occurs.
public static IEnumerable Retry(this IEnumerable source)
{
if (source == null)
throw new ArgumentNullException("source");
return new[] { source }.Repeat().Catch();
}
///
/// Creates a sequence that retries enumerating the source sequence as long as an error occurs, with the specified maximum number of retries.
///
/// Source sequence element type.
/// Source sequence.
/// Maximum number of retries.
/// Sequence concatenating the results of the source sequence as long as an error occurs.
public static IEnumerable Retry(this IEnumerable source, int retryCount)
{
if (source == null)
throw new ArgumentNullException("source");
if (retryCount < 0)
throw new ArgumentOutOfRangeException("retryCount");
return new[] { source }.Repeat(retryCount).Catch();
}
}
}