Metalama October 2025 Update: Full Steam Ahead Toward 2026.0
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:
- General status board highlighting the leftovers for the 2026.0 version.
- C# 14 status board showing our progress with C# 14 features.
Out of scope for Metalama 2026.0:
- Using null-conditional assignments in templates. #1109
- Using the
fieldkeyword in templates. #1114 - Introducing new extension blocks. #1159
Introducing extension members into existing extension blocks. #1160UPDATE: 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
IExtensionBlockinterface (TypeKind = Extension). It derives fromINamedType, and adds two properties:ReceiverParameterandReceiverType. Although extension blocks derive fromINamedType, 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.DeclaringTypepoints to theIExtensionBlock. - Extension blocks show up under
INamedType.ExtensionBlocks, not as nested types (INamedType.Types). - Extension methods and property accessors are listed in
INamedType.Methodsas 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
checkedoperators. - 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