-
Notifications
You must be signed in to change notification settings - Fork 735
/
Catch.cs
150 lines (127 loc) · 5.55 KB
/
Catch.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// 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.Collections.Generic;
namespace System.Linq
{
public static partial class EnumerableEx
{
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="TSource">Source sequence element type.</typeparam>
/// <typeparam name="TException">Exception type to catch.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="handler">Handler to invoke when an exception of the specified type occurs.</param>
/// <returns>Source sequence, concatenated with an exception handler result sequence in case of an error.</returns>
public static IEnumerable<TSource> Catch<TSource, TException>(this IEnumerable<TSource> source, Func<TException, IEnumerable<TSource>> handler)
where TException : Exception
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (handler == null)
throw new ArgumentNullException(nameof(handler));
return CatchCore(source, handler);
}
/// <summary>
/// Creates a sequence by concatenating source sequences until a source sequence completes successfully.
/// </summary>
/// <typeparam name="TSource">Source sequence element type.</typeparam>
/// <param name="sources">Source sequences.</param>
/// <returns>Sequence that continues to concatenate source sequences while errors occur.</returns>
public static IEnumerable<TSource> Catch<TSource>(this IEnumerable<IEnumerable<TSource>> sources)
{
if (sources == null)
throw new ArgumentNullException(nameof(sources));
return CatchCore(sources);
}
/// <summary>
/// Creates a sequence by concatenating source sequences until a source sequence completes successfully.
/// </summary>
/// <typeparam name="TSource">Source sequence element type.</typeparam>
/// <param name="sources">Source sequences.</param>
/// <returns>Sequence that continues to concatenate source sequences while errors occur.</returns>
public static IEnumerable<TSource> Catch<TSource>(params IEnumerable<TSource>[] sources)
{
if (sources == null)
throw new ArgumentNullException(nameof(sources));
return CatchCore(sources);
}
/// <summary>
/// Creates a sequence that returns the elements of the first sequence, switching to the second in case of an error.
/// </summary>
/// <typeparam name="TSource">Source sequence element type.</typeparam>
/// <param name="first">First sequence.</param>
/// <param name="second">Second sequence, concatenated to the result in case the first sequence completes exceptionally.</param>
/// <returns>The first sequence, followed by the second sequence in case an error is produced.</returns>
public static IEnumerable<TSource> Catch<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
{
if (first == null)
throw new ArgumentNullException(nameof(first));
if (second == null)
throw new ArgumentNullException(nameof(second));
return CatchCore(new[] { first, second });
}
private static IEnumerable<TSource> CatchCore<TSource, TException>(IEnumerable<TSource> source, Func<TException, IEnumerable<TSource>> handler)
where TException : Exception
{
var err = default(IEnumerable<TSource>);
using (var e = source.GetEnumerator())
{
while (true)
{
TSource c;
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<TSource> CatchCore<TSource>(IEnumerable<IEnumerable<TSource>> sources)
{
var error = default(Exception);
foreach (var source in sources)
{
using var e = source.GetEnumerator();
error = null;
while (true)
{
TSource c;
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;
}
}
}