| 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
staticmethod 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.