Bläddra i källkod

Ix: Implement the Retry() operator directly

Dávid Karnok 7 år sedan
förälder
incheckning
c6e751a313
1 ändrade filer med 104 tillägg och 5 borttagningar
  1. 104 5
      Ix.NET/Source/System.Interactive/Retry.cs

+ 104 - 5
Ix.NET/Source/System.Interactive/Retry.cs

@@ -21,8 +21,7 @@ namespace System.Linq
                 throw new ArgumentNullException(nameof(source));
             }
 
-            return new[] { source }.Repeat()
-                                 .Catch();
+            return RetryInfinite(source);
         }
 
         /// <summary>
@@ -45,8 +44,108 @@ namespace System.Linq
                 throw new ArgumentOutOfRangeException(nameof(retryCount));
             }
 
-            return new[] { source }.Repeat(retryCount)
-                                 .Catch();
+            return RetryFinite(source, retryCount);
+        }
+
+        private static IEnumerable<TSource> RetryInfinite<TSource>(IEnumerable<TSource> source)
+        {
+            while (true)
+            {
+                var enumerator = default(IEnumerator<TSource>);
+                try
+                {
+                    enumerator = source.GetEnumerator() ?? throw new NullReferenceException();
+                }
+                catch
+                {
+                    continue;
+                }
+
+                using (enumerator)
+                {
+                    var continueOuter = false;
+                    while (true)
+                    {
+                        var v = default(TSource);
+
+                        try
+                        {
+                            if (!enumerator.MoveNext())
+                            {
+                                yield break;
+                            }
+                            v = enumerator.Current;
+                        }
+                        catch
+                        {
+                            continueOuter = true;
+                            break;
+                        }
+
+                        yield return v;
+                    }
+
+                    if (continueOuter)
+                    {
+                        continue;
+                    }
+                }
+            }
+        }
+
+        private static IEnumerable<TSource> RetryFinite<TSource>(IEnumerable<TSource> source, int retryCount)
+        {
+            var lastException = default(Exception);
+
+            for (var i = 0; i < retryCount; i++)
+            {
+                var enumerator = default(IEnumerator<TSource>);
+                try
+                {
+                    enumerator = source.GetEnumerator() ?? throw new NullReferenceException();
+                }
+                catch (Exception ex)
+                {
+                    lastException = ex;
+                    continue;
+                }
+
+                using (enumerator)
+                {
+                    var continueOuter = false;
+                    while (true)
+                    {
+                        var v = default(TSource);
+
+                        try
+                        {
+                            if (!enumerator.MoveNext())
+                            {
+                                yield break;
+                            }
+                            v = enumerator.Current;
+                        }
+                        catch (Exception ex)
+                        {
+                            lastException = ex;
+                            continueOuter = true;
+                            break;
+                        }
+
+                        yield return v;
+                    }
+
+                    if (continueOuter)
+                    {
+                        continue;
+                    }
+                }
+            }
+
+            if (lastException != null)
+            {
+                throw lastException;
+            }
         }
     }
-}
+}