Share via


AsyncLazy<T>.SuppressRelevance Method

Definition

Marks the code that follows as irrelevant to the receiving AsyncLazy<T> value factory.

public Microsoft.VisualStudio.Threading.AsyncLazy<T>.RevertRelevance SuppressRelevance ();
member this.SuppressRelevance : unit -> Microsoft.VisualStudio.Threading.AsyncLazy<'T>.RevertRelevance
Public Function SuppressRelevance () As AsyncLazy(Of T).RevertRelevance

Returns

A value to dispose of to restore relevance into the value factory.

Remarks

In some cases asynchronous work may be spun off inside a value factory. When the value factory does not require this work to finish before the value factory can complete, it can be useful to use this method to mark that code as irrelevant to the value factory. In particular, this can be necessary when the spun off task may actually include code that may itself await the completion of the value factory itself. Such a situation would lead to an InvalidOperationException being thrown from GetValueAsync(CancellationToken) if the value factory has not completed already, which can introduce non-determinstic failures in the program.

A using block around the spun off code can help your program achieve reliable behavior, as shown below.

class MyClass {
  private readonly AsyncLazy<int> numberOfApples;

  public MyClass() {
    this.numberOfApples = new AsyncLazy<int>(async delegate {
      // We have some fire-and-forget code to run.
      // This is *not* relevant to the value factory, which is allowed to complete without waiting for this code to finish.
      using (this.numberOfApples.SuppressRelevance()) {
        this.FireOffNotificationsAsync();
      }

      // This code is relevant to the value factory, and must complete before the value factory can complete.
      return await this.CountNumberOfApplesAsync();
    });
  }

  public event EventHandler? ApplesCountingHasBegun;

  public async Task<int> GetApplesCountAsync(CancellationToken cancellationToken) {
    return await this.numberOfApples.GetValueAsync(cancellationToken);
  }

  private async Task<int> CountNumberOfApplesAsync() {
    await Task.Delay(1000);
    return 5;
  }

  private async Task FireOffNotificationsAsync() {
    // This may call to 3rd party code, which may happen to call back into GetApplesCountAsync (and thus into our AsyncLazy instance),
    // but such calls should *not* be interpreted as value factory reentrancy. They should just wait for the value factory to finish.
    // We accomplish this by suppressing relevance of the value factory while this code runs (see the caller of this method above).
    this.ApplesCountingHasBegun?.Invoke(this, EventArgs.Empty);
  }
}

If the AsyncLazy<T> was created with a JoinableTaskFactory, this method also calls SuppressRelevance() on the Context associated with that factory.

Applies to