Open sandboxFocusImprove this doc

LAMA0878: A lambda in a durable position captures a value that isn't durable

Severity Warning
Reported by Metalama.Framework (Roslyn analyzer)
Message This lambda is used where a durable value is required, and it captures '<CapturedVariable>', which is not durable. Retention path: <Path>.

Cause

At design time, the process that analyzes your code lives as long as the solution is open, while Roslyn creates a new compilation on almost every keystroke. An object that outlives a single request must therefore not hold, directly or indirectly, a compilation, a syntax tree, a symbol, a code-model declaration, or any other value that keeps a version of the project in memory. Types, fields, properties, and parameters that must follow this rule are marked with the [Durable] attribute.

A delegate always holds its target and everything its closure captured. That's why the declared type of a delegate is never durable, but an individual delegate can be. A [Durable] field, property, or parameter of a delegate type is allowed, provided that the analyzer can see that every value stored in it or passed to it captures only durable values. A static method group captures nothing, and a lambda is analyzed for what it actually uses.

Metalama reports LAMA0878 when all the following conditions are met:

  • A lambda expression, an anonymous method, or an instance method group is assigned to a [Durable] field or property, used as its initializer, or passed as an argument to a [Durable] parameter.
  • The lambda uses a local variable or a parameter whose type isn't durable, or uses the enclosing instance (this) when the type of that instance isn't durable. A method group is reported when its receiver isn't durable.

In the message, <CapturedVariable> is the name of the captured variable, or this when the lambda captures the enclosing instance. <Path> is the chain of types that leads from the captured variable to the value that isn't durable, for example a variable of a type that has a field of type Compilation. The warning is reported on the use of the captured variable inside the lambda.

This diagnostic is reported by a Roslyn analyzer, which snapshot tests don't run, so it can't be shown in an example.

Resolution

Choose one of the following options:

  • Make the lambda static, so that it captures nothing, and pass the values it needs as parameters of the delegate.
  • Capture only durable values. Instead of capturing a declaration, a symbol, or a compilation, capture a durable reference, such as an IDurableRef<T>, or an identifier, and resolve it against the current compilation when the delegate runs.
  • Use a static method as a method group instead of a lambda.
  • For a value that must be computed lazily, use DurableLazy<T> instead of Lazy<T>, which holds its factory delegate and therefore its closure.
  • If you know that the retention is harmless, suppress the warning, for instance with #pragma warning disable LAMA0878, and justify the suppression in a comment.

See also