From e788f88bb8acbbcbe829f815b165912d8fd0be29 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 24 Aug 2026 14:45:39 -0600 Subject: [PATCH 1/2] Stabilize AsyncLazy value factory collection test Remove the async helper state machine from the GC-sensitive test and keep the AsyncLazy rooted while verifying that its completed value factory is released. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 48b3b634-f1dc-4956-9b85-9ecd24ede8ac --- .../AsyncLazyTests.cs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs b/test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs index 051c960d5..db49838d6 100644 --- a/test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs +++ b/test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs @@ -149,11 +149,10 @@ async delegate } [Fact] - public async Task ValueFactoryReleasedAfterExecution() + public void ValueFactoryReleasedAfterExecution() { - WeakReference collectible = await this.ValueFactoryReleasedAfterExecution_Helper(); + (WeakReference collectible, AsyncLazy lazy) = this.ValueFactoryReleasedAfterExecution_Helper(); - await Task.Yield(); for (int i = 0; i < 3; i++) { GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true); @@ -161,6 +160,7 @@ public async Task ValueFactoryReleasedAfterExecution() } Assert.False(collectible.IsAlive); + GC.KeepAlive(lazy); } [Theory, CombinatorialData] @@ -1070,18 +1070,14 @@ private JoinableTaskContext InitializeJTCAndSC() } [MethodImpl(MethodImplOptions.NoInlining)] - private async Task ValueFactoryReleasedAfterExecution_Helper() + private (WeakReference Collectible, AsyncLazy Lazy) ValueFactoryReleasedAfterExecution_Helper() { - var closure = new { value = new object() }; - var collectible = new WeakReference(closure); - var lazy = new AsyncLazy(async delegate - { - await Task.Yield(); - return closure.value; - }); + var valueFactory = new ValueFactory(); + var collectible = new WeakReference(valueFactory); + var lazy = new AsyncLazy(valueFactory.CreateValueAsync); - await lazy.GetValueAsync(); - return collectible; + _ = lazy.GetValue(); + return (collectible, lazy); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -1119,6 +1115,11 @@ private abstract class DisposableBase public bool IsDisposed => this.disposalEvent.IsSet; } + private sealed class ValueFactory + { + internal Task CreateValueAsync() => Task.FromResult(new object()); + } + private class Disposable : DisposableBase, IDisposableObservable { public void Dispose() => this.disposalEvent.Set(); From 6fff3e7e372a80f240da245cc670937b5cc995b0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 24 Aug 2026 14:52:56 -0600 Subject: [PATCH 2/2] Document AsyncLazy test factory helper Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 48b3b634-f1dc-4956-9b85-9ecd24ede8ac --- test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs b/test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs index db49838d6..21254abed 100644 --- a/test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs +++ b/test/Microsoft.VisualStudio.Threading.Tests/AsyncLazyTests.cs @@ -1117,6 +1117,9 @@ private abstract class DisposableBase private sealed class ValueFactory { + /// + /// Creates the value returned by the test factory. + /// internal Task CreateValueAsync() => Task.FromResult(new object()); }