Browse Source

Ix.Async: Dispose an AsyncEnumerator once. (#559)

David Karnok 7 years ago
parent
commit
803bb72302

+ 21 - 0
Ix.NET/Source/System.Interactive.Async.Tests/AsyncTests.Creation.cs

@@ -452,6 +452,27 @@ namespace Tests
             await SequenceIdentity(xs);
         }
 
+        [Fact]
+        public async Task CreateEnumerator_DisposeOnce()
+        {
+            var count = 0;
+            var dispose = 0;
+
+            var en = AsyncEnumerable.CreateEnumerable(() =>
+                AsyncEnumerable.CreateEnumerator(async ct =>
+                {
+                    return ++count < 3;
+                }
+                , () => 1,
+                () => dispose++
+            ));
+
+            Assert.Equal(1, await en.Last());
+
+            Assert.Equal(3, count);
+            Assert.Equal(1, dispose);
+        }
+
         class MyD : IDisposable
         {
             private readonly Action _dispose;

+ 3 - 4
Ix.NET/Source/System.Interactive.Async/Create.cs

@@ -74,8 +74,8 @@ namespace System.Linq
         private sealed class AnonymousAsyncIterator<T> : AsyncIterator<T>
         {
             private readonly Func<T> currentFunc;
-            private readonly Action dispose;
             private readonly Func<CancellationToken, Task<bool>> moveNext;
+            private Action dispose;
 
 
             public AnonymousAsyncIterator(Func<CancellationToken, Task<bool>> moveNext, Func<T> currentFunc, Action dispose)
@@ -84,7 +84,7 @@ namespace System.Linq
 
                 this.moveNext = moveNext;
                 this.currentFunc = currentFunc;
-                this.dispose = dispose;
+                Volatile.Write(ref this.dispose, dispose);
 
                 // Explicit call to initialize enumerator mode
                 GetEnumerator();
@@ -97,8 +97,7 @@ namespace System.Linq
 
             public override void Dispose()
             {
-                dispose?.Invoke();
-
+                Interlocked.Exchange(ref this.dispose, null)?.Invoke();
                 base.Dispose();
             }