Metalama 2026.1 is a consolidation release, and the first long-term support (LTS) release of Metalama ever. It finishes the C# 14 story started in 2026.0, rounds out the initialization and parameter-introduction advice, ports major new features into the Redis caching backend, trims third-party dependencies, makes the design-time experience faster, and clears the entite bug backlog.
Highlights:
- C# 14 completion. Every feature listed as a limitation in Metalama 2026.0 is now implemented, including extension blocks introductions, constracts on extension block parameters, and introduction of C# 14 compound assignment operators.
- Initialization advice. New
AfterObjectInitializerandAfterLastInstanceConstructorkinds, records supported byBeforeInstanceConstructor, forwarding overloads for constructor parameter introduction, and parameter reuse for dependency injection. - Redis caching backend. Retry and exception-handling policies, key compression, overload detection, and many new configuration options.
- Reduced third-party dependencies.
System.Text.JsonreplacesNewtonsoft.Json,System.IO.HashingreplacesK4os.Hash, and optional HTML/diff-tool components have been extracted into opt-in extension packages. - Performance enhancements. Source-generated JSON serializers, MessagePack for design-time RPC, and pattern-matching optimizations.
- Over 100 bug fixes. Substantially the entire backlog.
Requirements
Metalama 2026.1 has the same requirements as 2026.0. See Requirements for the full matrix.
- Visual Studio 2022 LTSC 17.12, 2022 17.14, or 2026 18.0 (latest build).
- .NET SDK 8.0, 9.0, or 10.0.
- C# 12, 13, or 14.
C# 14 completion
All C# 14 features listed as limitations in Metalama 2026.0 are now implemented in 2026.1. The two most prominent additions (introducing C# 14 compound assignment operators and introducing extension blocks) are covered in their own sections below. The rest are closing gaps in template and advice support.
Introducing extension blocks
The new IntroduceExtensionBlock advice lets aspects introduce C# 14 extension blocks into a static class. You can specify the receiver type and an optional receiver parameter name to choose between instance and static extension blocks, and then add members with the usual IntroduceMethod, IntroduceProperty, and so on.
See Introducing types for a full example.
Contracts on extension-block receiver parameters
Contracts such as [NotNull] or Metalama.Patterns.Contracts attributes can now be applied to the receiver parameter of an extension block (#1127). Metalama propagates the contract to every extension member in the block, so a single declaration validates this-equivalent receiver access across the entire extension block, including members introduced by other aspects.
Introducing C# 14 compound assignment operators
Aspects can now introduce the new C# 14 compound assignment operators (+=, -=, *=, etc.) (#1131). Operator introduction goes through the standard IntroduceMethod advice by setting OperatorKind.
For details, see the Introducing operators section of Introducing members.
Other C# 14 completions
- #1109: Use null-conditional assignments in templates.
- #1114: Use the
fieldkeyword in templates. - #1036: Generate run-time code for extension members using invoker interfaces.
- #1143: Introduce parameters into partial constructors.
Initialization advice
Metalama 2026.1 significantly broadens how aspects advise object initialization. New initializer kinds cover modern C# object-construction patterns: primary constructors, object initializers, required and init-only properties, and with expressions. The companion IntroduceParameter advice can now preserve binary compatibility through forwarding constructors, in addition to preserving source compatibility through default values as in 2026.0.
AfterLastInstanceConstructor
InitializerKind.AfterLastInstanceConstructor injects your initialization logic into a protected virtual OnConstructed method and ensures it runs after all instance constructors in the chain have completed. An InitializationContext parameter threaded through the constructor chain coordinates this across inheritance hierarchies.
AfterObjectInitializer
InitializerKind.AfterObjectInitializer runs after the constructor and any object initializer or with expression have completed. Metalama makes the target type implement IInitializable and rewrites call sites to invoke Initialize automatically once construction and object initialization are done. This is the only reliable way to validate or compute derived state after all fields and properties have been set in the object initializer.
BeforeInstanceConstructor on records
InitializerKind.BeforeInstanceConstructor now supports records, including positional records. The initializer code is injected into the primary constructor.
See Adding initializers for examples.
Constructor parameter introduction with forwarding overloads
The IntroduceParameter advice now supports two mechanisms, both source-compatible:
- Adding an optional parameter: the overload taking a compile-time-constant
defaultValueadds the parameter directly to the existing constructor. The IL signature changes, so binary compatibility is not preserved. This was the only available strategy prior to 2026.1, and remains the right choice for dependency-injection scenarios. - Adding a required parameter, pulled from a forwarding constructor: the overload without
defaultValueadds the new parameter as required, and generates a forwarding constructor that retains the pre-mutation signature and chains to the mutated constructor via: this(...), preserving binary compatibility. The value supplied by the forwarding constructor comes from an IPullStrategy: for instance, UseExpression for a non-constant expression such asDateTime.Now.
The new ForwardSourceConstructors and ForwardDefaultConstructor strategies control when forwarding constructors are generated. Both expose a WithObsoleteAttribute method so generated constructors can be deprecated.
See Introducing constructor parameters.
Dependency injection
IntroduceParameterAndPull now accepts a reuseExistingParameterOfCompatibleType argument (#1552). When a chained constructor already accepts a parameter of the same or a more specific type, the existing parameter is forwarded instead of duplicated. The default .NET DI adapter relies on this: an aspect pulling ILogger<T> no longer adds a second ILogger<T> parameter if the target constructor already accepts one.
See Injecting dependencies into aspects.
Redis caching backend
The Redis caching backend has been significantly enhanced, with many features ported from PostSharp.Patterns.Caching. For full documentation, see Using Redis as a distributed cache.
Retry and exception-handling policies
Configurable retry and exception-handling policies are now exposed directly on RedisCachingBackendConfiguration, replacing the previous ExceptionHandlingCachingBackendEnhancer.
- Retry policies (IRetryPolicy): configurable retry logic with exponential backoff and jitter for transactions, background tasks, and recovery actions.
- Exception handling policies (IExceptionHandlingPolicy): control how exceptions are handled after retries are exhausted. The DefaultExceptionHandlingPolicy logs exceptions and attempts to recover from failed write operations.
Key compression
Cache keys that exceed a configurable threshold (default: 128 characters) can now be automatically hashed using the CacheKeyHashingAlgorithm enum (XxHash64 or XxHash128), avoiding Redis key length limits and improving performance with long keys.
Overload detection
<xref:Metalama.Patterns.Caching.Backends.Redis.RedisCachingBackend> now monitors its background task queue and exposes <xref:Metalama.Patterns.Caching.Backends.Redis.RedisCachingBackend.IsBackgroundTaskQueueOverloaded> and <xref:Metalama.Patterns.Caching.Backends.Redis.RedisCachingBackend.IsBackgroundTaskQueueOverloadedChanged>. The RedisCacheDependencyGarbageCollector automatically pauses real-time notification processing when the backend is overloaded.
New configuration options
New properties on RedisCachingBackendConfiguration:
TransactionRetryPolicy,BackgroundTasksRetryPolicy,BackgroundRecoveryRetryPolicyfor resilience.BackgroundTasksMaxConcurrencyandBackgroundTasksOverloadedThresholdfor overload management.InvalidationMaxConcurrencyfor throttling large graph invalidations.KeyCompressingThresholdfor key compression.DisposeTimeout,SupportsEvents,ReadCommandFlags,WriteCommandFlags.
The RedisCacheDependencyGarbageCollectorOptions class now provides configuration for the periodic cleanup process, including CacheCleanupDelay and CacheCleanupOptions (with RemediationDelay and MaxConcurrency).
Supply chain security
Metalama 2026.1 tightens its dependency footprint. Transitive dependencies that used to be forced on every Metalama user have either been replaced with platform-provided APIs or extracted into optional extension packages, so projects that don't need a given community-maintained component are no longer exposed to its risks.
System.Text.JsonreplacesNewtonsoft.Json(#741).System.IO.HashingreplacesK4os.Hash(#742). Non-cryptographic hashes now use xxHash from the .NET runtime libraries.- Diff-tool integration extracted to
Metalama.Extensions.DiffEngine(#446). Add the package to have the diff tool launched automatically when an aspect test fails; without it, tests run normally and the diff tool is silently disabled. See Snapshot testing of aspects and Configuring the external diff tool. - HTML test output extracted to
Metalama.Extensions.HtmlWriter(#447). The only typical use of this package is the generation of Metalama's own documentation. - MD5 is no longer used internally for non-cryptographic hashing (#525), so Metalama assemblies no longer trip security scanners that flag MD5 usage regardless of intent.
Performance enhancements
Several parts of the Metalama pipeline have been rewritten for speed:
- Source-generated JSON serializers. Metalama now uses
System.Text.Jsonsource generators for its configuration files. - MessagePack for design-time RPC (#1299). The protocol between the Metalama analyzer and the design-time services has been migrated from JSON to MessagePack.
- Pattern-matching optimization. Polymorphic matching on interface types has been restructured into matching by
DeclarationKindorTypeKind.
Other enhancements
Contracts
All numeric contracts in Metalama.Patterns.Contracts now accept types implementing INumber<T> (including generic type parameters), in addition to built-in numeric types (#1543).
See the Generic math support section of List of contract attributes.
Code model
- ICompilation.EntryPoint returns the
Program.Mainmethod of the compilation, ornullfor library projects. - IEvent.RaiseMethod returns
nullfor events that cannot be raised (non-field-like, interface, and abstract events). The new IEventInvoker.CanRaise property lets you check before attempting to raise (#771). OfExactSignatureoverloads on IMethodCollection and IConstructorCollection (#846) locate methods or constructors by exact signature.- Generic parameter constraints are now honored when matching signatures on IMethodCollection (#842).
- TypeFactory.TryGetType returns
falseinstead of throwing when a type cannot be resolved.
Templates and compile-time code
- TypedConstant.NamedConstant creates a
TypedConstantthat references an enum member or aconstfield by name, for instance run-time-only enum value. - IMethodInvoker.CreateDelegateExpression generates an expression that references a method as a delegate. Useful when you need to pass a method reference (e.g., to
EventHandlerorFunc<…>) rather than invoke it. See Generating code based on the code model. - Compile-time serialization now supports value tuples (
ValueTuplethroughValueTuple<T1,…,T7,TRest>) and Index/Range. See Serialization of aspects and other compile-time classes.
Fabrics
ITypeAmender now implements IAdviser<T> (#1487), so you can call IntroduceMethod, Override, ImplementInterface, and every other extension method from AdviserExtensions directly on the amender parameter; no more amender.Advice.* boilerplate. Use With to target a specific member.
A new Diagnostics property of type ScopedDiagnosticSink (#724) lets you report or suppress diagnostics scoped to the target type, just as you would from an aspect's BuildAspect method.
See Advising a single type with a fabric.
IDE and tooling
You can now hide an aspect from Aspect Explorer via a the HideFromAspectExplorer property of the EditorExperienceAttribute attribute (#697).
Deep backlog fixes
Beyond the feature work, Metalama 2026.1 is the release in which we processed substantially the entire bug backlog. More than 100 bug fixes shipped across the 2026.1 preview builds, addressing long-standing issues across the template engine, linker, code model, design-time services, dependency injection, and diagnostics. Many of these bugs had been open for a long time; clearing them is a feature in its own right.
For the full, per-build list of fixes, see the 2026.1 releases on GitHub.
Breaking changes
AddInitializerordering (#1529): initializer order now respectsAspectOrderDirection.RunTime. If you define an ordering with[assembly: AspectOrder(AspectOrderDirection.RunTime, typeof(FirstAspect), typeof(SecondAspect))], the initializer fromFirstAspectruns before the one fromSecondAspect.IntroduceParameteron record primary constructors (#1555): the introduced parameter is no longer materialized as part of the record's value shape by default: it does not generate an auto-property, does not appear inDeconstruct, and does not participate inEquals,GetHashCode, orToString. Opt in explicitly withPullStrategy.IntroduceParameterAndPull(materializeOnRecord: true).- IConstructor.InitializerKind now returns
Base(instead ofNone) for implicitbase()calls. - TemplateAttribute.IsVirtual is disregarded when the target type is
sealed. - IEvent.RaiseMethod returns
nullfor events that cannot be raised. Use IEventInvoker.CanRaise to check before raising. - Removed test base classes: the
AspectTestClass,DefaultAspectTestClass,CurrentDirectoryAttribute, andCurrentProjectAttributeclasses have been removed fromMetalama.Testing.AspectTesting. Tests are now discovered automatically; no test-runner code is needed.
Redis caching
- Data schema redesign: the Redis data schema has been redesigned. A cache purge (
FLUSHDB) is required after upgrading to 2026.1. - Removed
ExceptionHandlingCachingBackendEnhancer: use the ExceptionHandlingPolicy property instead. TransactionMaxRetriesis obsolete: use TransactionRetryPolicy instead.CacheCleanupOptions.Sequentialis obsolete: use MaxConcurrency instead.CacheValue.Dependencies/CacheItem.Dependencies: now expose first-level dependencies only (not recursive).