Metalama Status Update, September 2025
Welcome to Metalama’s September 2025 status update. After a relaxed summer, we’re back in full swing, delivering .NET 10 SDK support for Metalama and closing a key gap versus PostSharp: the ability to override event handler invocations.
This article was first published on the Metalama Blog.
Our first community contributor

Let me start with the announcement that brings me the greatest joy.
This past summer, Metalama received its first contribution from the open-source community. Giuseppe Marazzi submitted two PRs fixing two small and hard-to-find bugs.
A warm thanks to Giuseppe!
While Metalama may look like a complex codebase at first glance, Giuseppe’s contribution proves that anyone can make a meaningful impact. Don’t let the technical depth intimidate you: every contribution, no matter how small, is valuable and welcome! We’re here to help if you want to get involved! Check out our contributor’s guide to learn how to get started.
.NET SDK 10 readiness
As autumn arrives, Microsoft is finalizing the new .NET stack, and, like all .NET extenders, we’re working hard to make sure you can use the new features as soon as possible.
We’ve split the work into two releases:
- Metalama 2025.1 received quick fixes to keep working with the .NET 10 SDK, with limitations;
- Metalama 2026.0 will be built natively for the .NET 10 SDK.
Metalama 2025.1: limited .NET SDK 10 support
With the .NET SDK 10 already in RC, we didn’t want you to wait for full integration, so we made small changes to ensure compatibility with the new .NET SDK.
This build is Metalama 2025.1.14, released this week. From our platform integration matrix tests, most .NET workloads are working.
Keep in mind that Metalama 2025.1 is still based on Roslyn 4.14, while the .NET SDK 10 includes Roslyn 5.0. This has some implications:
- Analyzers and source generators compiled against Roslyn 5.0 will not work. When possible, we replace them with an older Roslyn 4.14 version—this often works, but not always.
- Specifically, Blazor projects (all flavors) are not supported yet because of an incompatibility in their source generators.
- You cannot use C# 14 features in your Metalama projects.
Metalama 2026.0 in progress
The goal of Metalama 2026.0 is to bring full native support for the .NET 10 SDK and C# 14 — native, not hacks.
C# 14 brings a lot of new features, and we won’t support all of them in every scenario in November, when the new .NET is expected to become generally available. Our primary goal with Metalama 2026.0 is to let you safely use any new C# feature in your runtime code—but not necessarily in aspect templates. Support for new language features in templates may come in later versions. This aligns with our design philosophy: Metalama should be able to compile any valid C# code, but it’s okay to limit features available in aspects.
We’re using GitHub to track our progress. You can use this meta-issue or this dashboard to check the status.
We plan to have an RC ready in November, when Microsoft is expected to release the new stack.
If you’re eager for a preview, look for one next week — or, if you’re more patient, compile the develop/2026.0 branch of Metalama and Metalama.Compiler repos (merged from Roslyn tag NET-SDK-10.0.100-preview.7.25380.108 as of today).
Visual Studio 2026 readiness
We ran some initial tests of our Metalama Tools for Visual Studio with Visual Studio 2026—and they failed, subtly but miserably.
It seems those incompatibilities can be addressed with fairly small bug fixes. If that proves to be true, we’ll update our tooling 2025.1 to support Visual Studio 2026 — and there will be no need to wait for Metalama 2026.0.
Metalama 2025.2 RC: Event invocation overrides
We have just released the first—and hopefully final—RC of Metalama 2025.2.
Since the beginning, Metalama has allowed overriding the add and remove accessors of events, which were arguably of limited utility. This version adds the ability to override the invocation of event handlers. The OverrideInvoke method of the OverrideEventAspect class lets you intercept the invocation of an individual event handler.
Typical use cases are:
- safe events (exception handling)
- background/asynchronous events
- event invocation logging
Let’s illustrate this with an example. This aspect catches exceptions in event handlers; if any exception is caught, it removes it from the event invocation list.
public class SafeEventAttribute : OverrideEventAspect
{
// If there are many event handlers, this method will be called several times.
public override dynamic? OverrideInvoke( dynamic? handler )
{
try
{
return meta.Proceed();
}
catch ( Exception e )
{
Console.WriteLine( e );
// First time shame on you, second time shame on me.
meta.Target.Event.Remove( handler );
throw;
}
}
}
We can now add this to any event:
public class Camera
{
[SafeEvent]
public event EventHandler? FocusChanged;
private void OnFocusChanged()
{
this.FocusChanged?.Invoke( this, EventArgs.Empty );
}
}
As you might expect, it took us a while to implement—it’s far from simple.
Here’s how Metalama transforms your code:
public class Camera
{
// The field backing the event.
private event EventHandler? _focusChanged;
// A broker sitting between the event API and the backing field.
private volatile ActionEventBroker<EventHandler?, (object?, EventArgs)>? _focusChangedBroker;
// Binds the broker to the event implementation and the advice.
private static readonly ActionEventBrokerCallbacks<EventHandler?, (object?, EventArgs)> FocusChangedBrokerCallbacks_0 = new (
static (handler, me, args) => ((Camera)me).FocusChanged_Invoke_SafeEvent(handler, args),
static b => (sender, e) => b.Invoke((sender, e)),
static (handler, me) => ((Camera)me).FocusChanged_SafeEvent += handler,
static (handler, me) => ((Camera)me).FocusChanged_SafeEvent -= handler );
// The public event with the new implementation.
[SafeEvent]
public event EventHandler? FocusChanged
{
add
{
ActionEventBroker<EventHandler?, (object?, EventArgs)>.EnsureInitialized(ref this._focusChangedBroker, this, FocusChangedBrokerCallbacks_0);
this._focusChangedBroker.AddHandler(value);
}
remove
{
this._focusChangedBroker?.RemoveHandler(value);
}
}
// The original event implementation.
private event EventHandler? FocusChanged_SafeEvent
{
add
{
this._focusChanged += value;
}
remove
{
this._focusChanged -= value;
}
}
// Your advice intercepting the handler invocation.
private void FocusChanged_Invoke_SafeEvent(EventHandler? handler, (object? sender, EventArgs e) args)
{
try
{
handler.Invoke(args.sender, args.e);
return;
}
catch (Exception e)
{
Console.WriteLine(e);
_focusChanged -= handler;
return;
}
}
private void OnFocusChanged()
{
this._focusChanged?.Invoke(this, EventArgs.Empty);
}
}
It’s a bit lengthy, but aside from a touch of syntactic sugar, the event broker is the most reliable pattern, because we can’t predict or analyze how an event is raised. This approach is oblivious to the event’s implementation and to how it gets raised.
You can find more details on this documentation page.
Subscribe to our briefs to receive updates about ongoing work on Metalama 2026.0 before the next monthly update.
Dockerization of our build infrastructure
As a side note, the entire Metalama build infrastructure now runs on Docker, requiring only lean build agents.
That means you can build Metalama in the exact environment we use.
All you need is a Windows 11 or Windows Server 2025 machine with Docker installed and Windows containers enabled, then run:
.\DockerBuild.ps1 build
Summary
On the feature side, the OverrideEventAspect.OverrideInvoke advice closes one of Metalama’s remaining gaps with PostSharp. On the platform front, we’ve released the first bits of .NET 10 support and we expect to deliver more soon. In terms of infrastructure, Dockerizing our build workflow makes Metalama easy to reproduce across agents and helps reduce the cost and complexity of our setup.
Happy meta-programming with Metalama!