Declares that a type must be written in an immutable style, and requires every type that derives from it or implements it to be written that way too. An analyzer verifies the declaration and reports a warning when it does not hold.
Namespace: Metalama.Framework.Utilities
Assembly: Metalama.Framework.dll
Syntax
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct|AttributeTargets.Interface, Inherited = false)]
public sealed class ImmutableTypeAttribute : AttributeRemarks
An aspect is instantiated once and reused for every target it applies to, and at design time across compilations. State kept on it therefore leaks from one target to the next, in an order the author does not control. That is why IAspect and Fabric carry this attribute, and why every aspect, fabric and validator is checked.
Concretely, in a type subject to this contract:
-
every instance field must be
readonly, or private and assigned only in a constructor or aninitaccessor; -
every automatically implemented property must have no setter, an
initaccessor, or a private setter assigned only in a constructor or aninitaccessor; - and the type of every such member must itself be immutable, all the way down.
A member whose write access is private is checked at its assignments rather than at its declaration, because
private write access confines every assignment to the declaring type, so the analyzer can see all of them.
Passing such a member as a ref or out argument counts as an assignment.
Intrinsic types, delegates, enumerations and the immutable collections are immutable, and an immutable collection is immutable only when its type arguments are. A type that is not marked with this attribute and is not otherwise known to the analyzer is not immutable, so marking a type propagates the obligation to the types of all of its members.
This attribute is deliberately not System.ComponentModel.ImmutableObjectAttribute. That one
exists to tell a designer that an object has no editable sub-properties, it is applied in the wild for that
reason, and it says nothing about this contract. Reusing it would mean checking code whose author never opted
in. The name also avoids Metalama.Patterns.Immutability.ImmutableAttribute, which is a different feature
and may be imported in the same file.
There is deliberately no per-type waiver. Where the contract is genuinely not wanted on one declaration, the
ordinary suppression mechanisms apply: #pragma warning disable, [SuppressMessage] with a
justification, or a severity in an .editorconfig. A project that implements the framework itself,
rather than using it, sets the MetalamaEnforceImmutabilityContract MSBuild property to false to
turn the contract off entirely.
Constructors
| Name | Description |
|---|---|
| ImmutableTypeAttribute() |