Metalama October 2025 Update: Full Steam Ahead Toward 2026.0

by Gael Fraiteur on 30 Oct 2025

October is traditionally our busiest month. Microsoft ships the RCs of the .NET SDK, C# and Visual Studio, and we sprint to make Metalama ready. This year is no exception: we’ve made solid progress, and we’re confident we’ll be ready on time for the GA wave. Below is a recap of what we shipped and what’s coming.

This article was first published on the Metalama Blog.

Metalama 2025.2: skipped for simplicity

We’ve decided not to ship Metalama 2025.2 as a standalone release. All its features, including the ability to override event handler invocations, are already merged into Metalama 2026.0. Why? The only real benefit of releasing 2025.2 would be making event-invocation advising available a few weeks earlier, but supporting two versions in parallel would slow us down.

Metalama 2026.0: almost there

We are now almost code-complete with Metalama 2026.0, and have released several previews:

.NET 10 SDK and C# 14

We’re nearly done with support for the .NET 10 SDK and C# 14. Want to see where things stand? Check out these resources:

Out of scope for Metalama 2026.0:

  • Using null-conditional assignments in templates. #1109
  • Using the field keyword in templates. #1114
  • Introducing new extension blocks. #1159
  • Introducing extension members into existing extension blocks. #1160 UPDATE: implemented in 2026.0.4-preview.

Fun fact: we noticed that compiling our NopCommerce snapshot with C# 14 breaks LINQ-to-SQL because of implicit conversions of arrays to ReadOnlySpan. We’ve had to pin this solution to C# 13 to work around this issue.

Extension blocks

“Extend everything” is the headline feature of C# 14, and we’re making sure Metalama supports it out of the box — including overriding extension members. Here’s how we’re modeling extension blocks:

  • Extension blocks use the IExtensionBlock interface (TypeKind = Extension). It derives from INamedType, and adds two properties: ReceiverParameter and ReceiverType. Although extension blocks derive from INamedType, you can’t always treat them like regular ones. Yes, this technically bends the Liskov Substitution Principle, but splitting the hierarchy would make the API noisier for little practical benefit. For extension members (except classic extension methods), IMember.DeclaringType points to the IExtensionBlock.
  • Extension blocks show up under INamedType.ExtensionBlocks, not as nested types (INamedType.Types).
  • Extension methods and property accessors are listed in INamedType.Methods as implicitly-implemented methods. They exist in IL and are addressable in C#, but you can’t override them with Metalama.

This approach feels natural for C# developers and closely matches Roslyn’s model.

First-class support for named tuples

Previously, Metalama treated tuples as plain INamedType objects, without access to element types or names. This made scenarios like packing method arguments for interceptors (think caching) awkward and inefficient. Now, with the new ITupleType interface, you get direct access to element names and types. Create named tuples with TypeFactory.CreateTupleType, and instantiate them with ITupleType.CreateCreateInstanceExpression.

Our implementation even supports tuples with zero or one element. For two or more, you get the nice tuple syntax; for degenerate cases, Metalama falls back to ValueTuple.Create(...). When you use ITupleType, you don’t have to worry about these details yourself.

Example: Want to advise multiple methods and pass all arguments to an observer? Here’s how:

// Create the tuple type.
var tupleType = TypeFactory.CreateTupleType(method.Parameters);

// Create the tuple instance.
var tupleExpression = tupleType.CreateCreateInstanceExpression(meta.Target.Parameters);

// Invoke the interceptor.
_myObserver.OnMethodCalled(method.DeclaringType.FullName, method.Name, tupleExpression.Value);

Transformed code:

// Two or more arguments: tuple syntax
public IEnumerable<Hat> FindHats(decimal size, string category)
{
    _myObserver.OnMethodCalled("HatStore", "FindHats", (size, category));
    // ...
}

// One argument: ValueTuple.Create
public bool IsHatAvailable(long hatId)
{
    _myObserver.OnMethodCalled("HatStore", "IsHatAvailable", ValueTuple.Create(hatId));
    // ...
}

// Zero arguments
public bool IsStoreOpen()
{
    _myObserver.OnMethodCalled("HatStore", "IsStoreOpen", ValueTuple.Create());
    // ...
}

Breaking Change: INamedType.TypeKind now returns Tuple instead of NamedType for tuples.

Advising event invocations

Overriding event handler invocation logic, originally planned for 2025.2, is now part of 2026.0. For details, see the September 2025 Status Update.

Other improvements

  • Introducing user-defined checked operators.
  • Dependency injection: pull constructor parameters across projects.
  • API cleanup (some breaking changes, [Obsolete] warnings).

Metalama 2025.1: now supports Visual Studio 2026

Last month, we added limited .NET 10 SDK support to Metalama 2025.1. As of October 7, Visual Studio 2026 is also supported.

Just make sure to update both the NuGet packages and the VSIX extension.

Roadmap: finalizing 2026.0

We’re wrapping up the last features for full C# 14 support in Metalama 2026.0. Next up: stabilization, code cleanup, manual testing, and performance validation.

We’re aiming for a release candidate (RC) on November 7, barring any surprises during testing. The final GA release will follow soon after Microsoft ships the GA versions of the .NET SDK and related packages.

Conclusion

In October, we made excellent progress with Metalama 2026.0, whose main focus is to support the .NET 10 SDK, C# 14, and Visual Studio 2026. We’re almost code complete, and we’ll spend most of November stabilizing the release.

Happy meta-programming!

-gael