Skip to main content

Advantages & Disadvantages

An honest assessment of Metalama's strengths, weaknesses, and when it's the right (or wrong) choice.


Advantages

1. Clean, Readable Source Code

The primary benefit. Cross-cutting concerns are declared as attributes, keeping business logic uncluttered:

// Without AOP: 30+ lines of infrastructure code per method
// With AOP: Business logic stands out clearly
[Authorize]
[Log]
[Cache(AbsoluteExpirationSeconds = 300)]
[Retry(MaxAttempts = 3)]
public async Task<Recipe> GetRecipeAsync(int id)
{
return await _repository.GetByIdAsync(id);
}

2. Zero Runtime Overhead

Unlike runtime proxy-based frameworks, Metalama generates the infrastructure code at compile time. The output assembly contains only normal method calls — no reflection, no dynamic dispatch, no proxy overhead.

Comparison:

FrameworkMechanismOverhead
MetalamaCompile-time code generationNone
Castle DynamicProxyRuntime proxy creationProxy instantiation + virtual dispatch
DispatchProxyRuntime proxy creationSame as Castle
Reflection-basedRuntime reflectionSignificant (reflection is slow)

3. Compile-Time Error Detection

Mistakes are caught during compilation, not at runtime:

[Cache]  // ❌ Compile error: "Cannot cache void methods"
public void ProcessOrder(Order order) { }

[NotifyPropertyChanged] // ❌ Compile error: "Class must be partial"
public class ViewModel { }

4. IDE Integration

Metalama integrates with Visual Studio and Rider:

  • Code lens shows which aspects are applied
  • Quick fixes suggest aspect application
  • Warnings and errors appear in the IDE
  • Generated code is browsable in obj/.../metalama/

5. Debuggable Generated Code

Unlike IL rewriting (PostSharp pre-2023), Metalama generates C# source code that you can:

  • Read and understand
  • Set breakpoints in
  • Step through with the debugger
  • Diff between versions

6. Separation of Concerns (True Modularity)

Each cross-cutting concern lives in one place:

  • Logging logic → LogAttribute.cs
  • Retry logic → RetryAttribute.cs
  • Audit logic → AuditAttribute.cs

Changing the logging format means modifying one file, not 200 methods.

7. Consistency

When logging is implemented in one aspect, every method that uses [Log] behaves identically. No risk of:

  • Different log formats in different methods
  • Forgotten try/catch blocks
  • Inconsistent error handling

8. Composability

Aspects can be stacked without conflicts:

[Log]           // ← These don't know about each other
[Retry] // ← But they compose naturally
[Cache] // ← Through the meta.Proceed() pipeline
public Result GetData() { }

9. Contract Inheritance

Validation contracts are inherited from interfaces, ensuring consistency across implementations without repetition.

10. Testability

Aspects can be tested independently:

  • Snapshot tests verify code generation
  • Run-time tests verify behavior
  • No need to test infrastructure code in every service

Disadvantages

1. Learning Curve

Metalama introduces several new concepts:

  • T# template language (compile-time vs. runtime code)
  • meta.* API
  • Code model interfaces (IMethod, IType, etc.)
  • Compile-time vs. run-time mental model

Mitigation: This guide exists to flatten the learning curve.

2. Build-Time Complexity

Metalama adds a step to the compilation pipeline:

  • Slower builds: Compile time increases (typically 10-30% for large projects)
  • Build dependencies: Metalama NuGet package must be available
  • CI/CD: Build servers need Metalama installed
  • Version sensitivity: Metalama version must match across projects

3. Debugging Indirection

While generated code is debuggable, the indirection can be confusing:

  • Source code doesn't match what runs
  • Breakpoints must be set in transformed code
  • Stack traces show generated method names
  • meta.DebugBreak() vs Debugger.Break() confusion

4. Hidden Behavior ("Magic")

Aspects add behavior that isn't visible at the call site:

service.GetData();  // ← Is this cached? Logged? Retried? You can't tell.

This can make code harder to reason about for developers unfamiliar with the aspects.

Mitigation: Good naming conventions ([Cache], [Retry]) and team documentation.

5. Vendor Lock-In

Metalama is the only mature compile-time AOP framework for modern .NET:

  • Migrating away requires rewriting all aspects as manual code
  • PostSharp (predecessor) is discontinued for new development
  • No open-source alternative with similar features

Mitigation: Aspects are well-encapsulated. If you need to remove Metalama, you can mechanically inline each aspect's behavior into the target methods.

6. Limited to C#

Metalama only works with C#:

  • No F# support
  • No VB.NET support
  • C++ interop projects unaffected (aspects only apply to C# code)

7. Partial Class Requirement

TypeAspect (which introduces members) requires target classes to be partial:

// Must be 'partial' to receive introduced members
[NotifyPropertyChanged]
public partial class ViewModel { }

This can feel intrusive, especially for existing codebases.

8. Service Locator Pattern (GST-Specific)

Because aspects are compile-time artifacts, they cannot use constructor injection. The GST framework uses AspectServiceLocator (a static service locator), which:

  • Is considered an anti-pattern in DI communities
  • Creates a hidden dependency on service initialization
  • Requires explicit InitializeAspects() call at startup

Mitigation: This is a Metalama limitation, not a design choice. The Metalama team is exploring better DI integration. The Metalama.Extensions.DependencyInjection package provides some alternatives.

9. Compile-Time Constraints

Template code must be compile-time safe:

  • Cannot use nameof() for introduced members
  • Cannot reference run-time-only APIs in compile-time code
  • foreach over parameters is unrolled (can produce large methods)
  • Some C# patterns don't work in templates

10. Licensing

Metalama has a commercial license model:

  • Free: Metalama Free for open-source and small projects
  • Essential: Paid license for commercial projects (some limitations)
  • Ultimate: Full feature set (higher cost)

Check metalama.net/pricing for current details.


Comparison with Alternatives

Metalama vs. PostSharp

AspectMetalamaPostSharp
GenerationNext-gen (source transformation)Legacy (IL rewriting)
Source visibilityGenerated C# code is readableIL is opaque
DebuggingStandard C# debuggingSpecial debugging tools needed
PerformanceSame or betterGood
EcosystemGrowingMature but declining
MigrationMigration guide availableN/A
StatusActive developmentMaintenance mode

Metalama vs. Castle DynamicProxy

AspectMetalamaCastle DynamicProxy
WeavingCompile-timeRuntime (proxy)
PerformanceZero overheadProxy overhead
ScopeAny method/property/fieldInterface/virtual methods only
SetupNuGet + attributesDI container registration
DebuggingGenerated C#Runtime proxy stack
Error detectionCompile-timeRuntime

Metalama vs. C# Source Generators

AspectMetalamaSource Generators
Can modify existing code✅ Yes❌ No (only add new code)
Template languageT# (high-level)Roslyn syntax tree (low-level)
Base classesRich (OverrideMethodAspect, etc.)None (DIY)
ComposabilityBuilt-in (aspect pipeline)Manual
Learning curveMediumHigh (Roslyn API)
IDE supportGoodGood

Metalama vs. Manual Code / No AOP

AspectMetalamaManual Code
ReadabilityClean (attributes)Cluttered (interleaved concerns)
ConsistencyGuaranteedDeveloper-dependent
MaintenanceChange in one placeChange in N places
Learning curveInitial investmentNone
Build complexityAdditional stepNone
DebuggingIndirectDirect

When to Use Metalama

Good Use Cases ✅

ScenarioWhy
Many methods with same infrastructureDRY — define once, apply everywhere
Compliance requirements (FDA, SOX)Consistent, auditable, certified aspect behavior
MVVM applications (WPF, MAUI)INotifyPropertyChanged boilerplate elimination
Library/framework developmentEnforce patterns on consumers
Large teamsConsistency despite varying developer skill levels
Long-lived codebasesCentralized concern management reduces maintenance

Poor Use Cases ❌

ScenarioWhy
Small projects (< 10 classes)Overhead not justified
Prototypes / throwaway codeOver-engineering
Single-developer scriptsNo consistency benefit
Performance-critical hot pathsThough overhead is minimal, extra generated code adds complexity
Teams unfamiliar with AOP (without training)"Magic" code causes confusion
Non-C# projectsNot supported

Summary

The Value Proposition

Metalama is most valuable when you have:

  1. ≥ 10 methods that share the same cross-cutting concern
  2. A need for consistency (compliance, team standards)
  3. Cross-cutting concerns that change over time (centralized modification)
  4. A team willing to invest in learning the framework

The Cost

  1. Learning curve for the team
  2. Build-time increase
  3. Debugging indirection
  4. Vendor dependency

Bottom Line

Metalama trades initial learning investment for long-term maintainability. For codebases with significant cross-cutting concerns (like the GST framework), the trade-off is overwhelmingly positive.

Next: Best Practices — Design principles and common pitfalls.