Catch.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Threading.Tasks;
  8. namespace System.Linq
  9. {
  10. public static partial class EnumerableEx
  11. {
  12. /// <summary>
  13. /// Creates a sequence that corresponds to the source sequence, concatenating it with the sequence resulting from
  14. /// calling an exception handler function in case of an error.
  15. /// </summary>
  16. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  17. /// <typeparam name="TException">Exception type to catch.</typeparam>
  18. /// <param name="source">Source sequence.</param>
  19. /// <param name="handler">Handler to invoke when an exception of the specified type occurs.</param>
  20. /// <returns>Source sequence, concatenated with an exception handler result sequence in case of an error.</returns>
  21. public static IEnumerable<TSource> Catch<TSource, TException>(this IEnumerable<TSource> source, Func<TException, IEnumerable<TSource>> handler)
  22. where TException : Exception
  23. {
  24. if (source == null)
  25. throw new ArgumentNullException(nameof(source));
  26. if (handler == null)
  27. throw new ArgumentNullException(nameof(handler));
  28. return source.Catch_(handler);
  29. }
  30. /// <summary>
  31. /// Creates a sequence by concatenating source sequences until a source sequence completes successfully.
  32. /// </summary>
  33. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  34. /// <param name="sources">Source sequences.</param>
  35. /// <returns>Sequence that continues to concatenate source sequences while errors occur.</returns>
  36. public static IEnumerable<TSource> Catch<TSource>(this IEnumerable<IEnumerable<TSource>> sources)
  37. {
  38. if (sources == null)
  39. throw new ArgumentNullException(nameof(sources));
  40. return sources.Catch_();
  41. }
  42. /// <summary>
  43. /// Creates a sequence by concatenating source sequences until a source sequence completes successfully.
  44. /// </summary>
  45. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  46. /// <param name="sources">Source sequences.</param>
  47. /// <returns>Sequence that continues to concatenate source sequences while errors occur.</returns>
  48. public static IEnumerable<TSource> Catch<TSource>(params IEnumerable<TSource>[] sources)
  49. {
  50. if (sources == null)
  51. throw new ArgumentNullException(nameof(sources));
  52. return sources.Catch_();
  53. }
  54. /// <summary>
  55. /// Creates a sequence that returns the elements of the first sequence, switching to the second in case of an error.
  56. /// </summary>
  57. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  58. /// <param name="first">First sequence.</param>
  59. /// <param name="second">Second sequence, concatenated to the result in case the first sequence completes exceptionally.</param>
  60. /// <returns>The first sequence, followed by the second sequence in case an error is produced.</returns>
  61. public static IEnumerable<TSource> Catch<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
  62. {
  63. if (first == null)
  64. throw new ArgumentNullException(nameof(first));
  65. if (second == null)
  66. throw new ArgumentNullException(nameof(second));
  67. return new[] {first, second}.Catch_();
  68. }
  69. private static IEnumerable<TSource> Catch_<TSource, TException>(this IEnumerable<TSource> source, Func<TException, IEnumerable<TSource>> handler)
  70. where TException : Exception
  71. {
  72. var err = default(IEnumerable<TSource>);
  73. using (var e = source.GetEnumerator())
  74. {
  75. while (true)
  76. {
  77. var c = default(TSource);
  78. try
  79. {
  80. if (!e.MoveNext())
  81. break;
  82. c = e.Current;
  83. }
  84. catch (TException ex)
  85. {
  86. err = handler(ex);
  87. break;
  88. }
  89. yield return c;
  90. }
  91. }
  92. if (err != null)
  93. {
  94. foreach (var item in err)
  95. yield return item;
  96. }
  97. }
  98. private static IEnumerable<TSource> Catch_<TSource>(this IEnumerable<IEnumerable<TSource>> sources)
  99. {
  100. var error = default(Exception);
  101. foreach (var source in sources)
  102. {
  103. using (var e = source.GetEnumerator())
  104. {
  105. error = null;
  106. while (true)
  107. {
  108. var c = default(TSource);
  109. try
  110. {
  111. if (!e.MoveNext())
  112. break;
  113. c = e.Current;
  114. }
  115. catch (Exception ex)
  116. {
  117. error = ex;
  118. break;
  119. }
  120. yield return c;
  121. }
  122. if (error == null)
  123. break;
  124. }
  125. }
  126. if (error != null)
  127. throw error;
  128. }
  129. }
  130. }