| Severity | Warning |
| Reported by | Metalama.Framework (Roslyn analyzer) |
| Message | '<Type>' must be written in an immutable style because it is an aspect, a fabric, a validator, or another type bound by the [ImmutableType] contract, but the field '<Field>' is neither read-only nor private, so not every assignment to it can be seen. Add the 'readonly' modifier, or make the field private. |
Cause
An aspect is instantiated once and reused for every declaration it applies to, and at design time it is reused across compilations. State that you keep in an aspect instance therefore leaks from one target to the next, in an order that you don't control. That's why Metalama requires aspects, fabrics, and validators to be written in an immutable style. The requirement comes from the [ImmutableType] attribute, which is applied to IAspect and Fabric, and which every type that derives from or implements a marked type inherits.
For such a type, every instance field must be read-only, or private and assigned only in a constructor or in an init accessor. A private field that isn't read-only is accepted at its declaration, because private write access confines every assignment to the declaring type, and the analyzer then checks the assignments themselves. A field that is public, internal, or protected can be written by code that the analyzer can't see, so the declaration itself is reported.
Metalama reports LAMA0880 on the declaration of an instance field that isn't static, const, readonly, or private. In the message, <Type> is the aspect, fabric, validator, or other type subject to the contract, and <Field> is the name of the field. Automatic properties are reported with LAMA0881.
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:
- Add the
readonlymodifier to the field and assign it in the constructor or in a field initializer. This is the preferred option. - Make the field private, and make sure that it is assigned only in a constructor.
- Replace the field with an automatic property that has an
initaccessor. - Move the state out of the aspect. Keep per-target state in the objects that your template or
BuildAspectmethod creates, and not in a field of the aspect.
If the type of the field isn't immutable either, Metalama reports it separately once the field is read-only.