Metalama Status Update, June 2024
The main focus this month was completing the new Metalama 2024.2 release. We’re now just a couple of days away from the RC. The coolest addition this month is the ability to add top-level classes. The INotifyPropertyChanged
and XAML aspects are now final. The introspection APIs and our LinqPad driver have been greatly improved.
Metalama 2024.0 and 2024.1
We published several bugfix releases for our supported versions. See the changelogs for details.
Following our product lifecycle and support guidelines, we announced on June 26th that Metalama 2024.0 came out of support. Metalama 2024.1 is our current stable release and will receive all bug fixes.
Progress on Metalama 2024.2
We’ve almost completed the development and testing work on Metalama 2024.2, which should be ready for RC next week. This new version should go GA by the end of July.
Type introduction
We finalized the work on class
introduction. It’s now possible to create nested or top-level classes using an aspect. The API has been finalized and documented.
We are particularly proud of the Builder pattern example.
public class BuilderAttribute : TypeAspect
{
public override void BuildAspect( IAspectBuilder<INamedType> builder )
{
base.BuildAspect( builder );
var builderType = builder
.With( builder.Target.GetNamespace()! )
.WithChildNamespace( "Builders" )
.IntroduceClass( builder.Target.Name + "Builder" );
var properties = builder.Target.Properties.Where( p => p.Writeability != Writeability.None && !p.IsStatic );
foreach ( var property in properties )
{
builderType.IntroduceAutomaticProperty(
property.Name,
property.Type );
}
// Details skipped for brevity.
}
}
Please refer to the online documentation for the complete code.
The Aspect Explorer, a tool window added by Visual Studio Tools for Metalama, now also displays the new top-level types introduced by an aspect. You can use this feature to preview the code of the generated type. This feature is still being stabilized.
Metalama.Patterns
We finished all planned work in Metalama.Patterns
, our collection of open-source and professionally-built aspects.
- We developed and published a new package
Metalama.Patterns.Immutability
to address the concept of immutable types. This concept is used in the[Observable]
aspect. For details, see the reference documentation. - We finalized the design and documentation of
Metalama.Patterns.Observability
(implementingINotifyPropertyChanged
) andMetalama.Patterns.Xaml
(implementing commands and dependency properties). For details, see the reference documentation for Observability and XAML. - We finally addressed the naming issues with the number contracts in
Metalama.Patterns.Contracts
, where[LessThan]
meant[LessThanOrEqual]
,[Positive]
meant[NonNegative]
, and so on. Using these ambiguous contracts will result in a warning, which can be resolved by configuring the contracts in a fabric or by using the new, non-ambiguous[NonNegative]
,[NonPositive]
,[GreaterThanOrEqual]
, or[LessThanOrEqual]
. For details, see the warning in the reference documentation.
Metalama.Framework.Workspaces and Metalama.LinqPad
We improved the Metalama.Framework.Workspaces
API, which allows you to analyze projects from any code, and our LinqPad driver, which lets you query the code interactively.
The most important additions are the extension methods IDeclaration.GetInboundReferences()
and IDeclaration.GetOutboundReferences
allowing you to navigate references from or to a declaration. The new extension method INamedType.GetDerivedTypes()
returns all types derived from the current named type within the current namespace.
It makes it extremely simple to verify source code from anywhere. The following snippet is a valid program that validates that the CodeQualityTalk.Abstractions
namespace does not have dependencies on other non-system namespaces.
var workspace = Workspace.Load(args[0]);
workspace.SourceCode.Types
.Where(t => t.ContainingNamespace.FullName == "CodeQualityTalk.Abstractions")
.SelectMany(t => t.GetOutboundReferences())
.Where(r =>
{
var ns = r.DestinationDeclaration.GetNamespace()!.FullName;
return ns.StartsWith("CodeQualityTalk") && ns != "CodeQualityTalk.Abstractions";
})
.Report(
Severity.Warning,
"MY003",
"The CodeQualityTalk.Abstractions namespace must not have dependencies on other namespaces.");
Other improvements
- Aspect API: We added a new mechanism to pass tags: they can now be set using the new
IAspectBuilder.Tags
property from theBuildAspect
method. This allows you to use tags in declarative advice, e.g. in[Introduce]
d declarations. - Supportability: It is now possible to trace to the system console to ease troubleshooting on build agents. For details, see here.
The Timeless .NET Engineer
We continued publishing articles on the Timeless .NET Engineer blog and newsletters.
The goal of this series is to educate .NET developers about building robust and maintainable applications with clean code. Metalama is often mentioned as a possible solution, but none of the articles are product-centric.
This month, we released three articles:
You can subscribe to this newsletter here.
Roadmap
Metalama 2024.2 is virtually completed and will be generally available by the end of July.
We don’t plan to start working on new features during the summer, but rather to focus on bug fixes and advocacy. And as every year during the summer, we will take some time off with our families. We plan to look at .NET 9.0 starting in September-October.
Conclusion
We can’t wait to release Metalama 2024.2. It’s a very cool version, and class introductions complete the vision I had back in 2020 when we started the project. You can now implement almost all patterns using Metalama—a dream I’ve been pursuing for 20 years, starting with PostSharp.
Happy meta-programming!