Metalama's Divorce feature injects all generated code back into your source files and strips out the framework. You get a codebase that compiles under the stock Microsoft compiler. Metalama gets its stuff and leaves.
Why a Divorce feature
A few years ago, while pitching PostSharp to an Israeli prospect, they asked if adopting the framework was, like a Catholic marriage, til death do us part. We didn't have a great answer. You could remove PostSharp, but you'd have to rewrite every line of generated code by hand, undoing years of accumulated time savings.
So we built Metalama to be the considerate partner. Want out? Run metalama divorce. It injects the generated code back into your source, disables Metalama in your projects, and steps aside. A few hours later you're compiling with the plain Microsoft compiler as if nothing happened.
You will, of course, lose everything that made the relationship work: deterministically auto-generated boilerplate, compile-time architecture validation, and the quiet confidence that your cross-cutting concerns are handled. You'll be writing that code by hand again. You might also use an AI: faster, but neither deterministic nor infallible. But Metalama isn't the kind of partner that makes you fight for custody of your own source files.
Before you file the papers, though — if something isn't working, talk to the Metalama team. Sometimes the problem has a fix, or Metalama can be extended to address it. We'd rather improve the framework than wave you goodbye. Think of us as the couples therapist who happens to know the framework's source code.
Step 0. Consider your decision carefully
Despite Metalama's best efforts, no divorce is truly painless.
The metalama divorce command injects a large amount of boilerplate into your source code. Before you proceed, weigh these consequences:
- You'll now have to maintain this boilerplate code manually.
- Metalama doesn't always generate code that a human would write. Your codebase may look non-idiomatic after the divorce. You can preview what Metalama does with your code using the feature described in Understanding your aspect-oriented code.
- The changes produce a large commit that will be difficult to merge if colleagues are working on other branches.
- Returning to Metalama after the divorce can be even more painful because you would need to remove the boilerplate manually, unless you can easily revert the divorce commit.
Step 1. Prepare your code
Format your code to your preferred standard using a tool like dotnet format or the Clean Up feature of ReSharper or Rider. Metalama's generated code will not respect your formatting rules, and you'll reformat again after the divorce, so starting from a clean baseline keeps the diff readable.
Warning
The pre-divorce formatting pass may surface pre-existing issues in your codebase that are unrelated to the divorce itself. For example, dotnet format code-fix analyzers can rewrite API calls in ways that don't compile without additional using directives. If this happens, fix the formatting issues first, verify the build still passes, and then proceed.
Ensure all your unit tests are successful.
Step 2. Commit your code
Ensure your code is committed. Create a separate branch for the divorce and check it out.
Step 3. Build your code with special flags
Open a terminal window.
Clean all
objandbindirectories throughout your solution before proceeding. The divorce tool copies whatever.transformedfiles it finds under each project'sobj/directory. If a prior build populatedobj/with output produced under different preprocessor constants or withoutMetalamaFormatOutput, those stale files will be copied back and the divorced code may fail to parse.Get-ChildItem -Path . -Recurse -Force -Directory | Where-Object { $_.Name -in 'obj', 'bin' } | Remove-Item -Recurse -ForceDefine the following environment variables:
$env:MetalamaEmitCompilerTransformedFiles="true" $env:MetalamaFormatOutput="true"Note that the syntax differs if you're not using PowerShell. You can also define these properties in
Directory.Build.props, but make sure they apply to all projects using Metalama.Rebuild all your projects. Don't miss any! Your build may take longer than usual due to the
MetalamaFormatOutputproperty.
Building the projects with these two properties will write the transformed code files to disk in the transformed directory, located under the obj directory of each project.
Step 4. Execute the divorce command
Install the metalama tool as described in Installing the Metalama command line tool.
Then, execute the following command from the root directory of your repository.
metalama divorce
This command will:
- Copy all files under the
obj/**/transformeddirectory back to their original location in the source code. - Set the
<MetalamaEnabled>MSBuild property tofalsein every.csprojfile, so subsequent builds use the standard Microsoft compiler instead of Metalama.
Step 5. Reformat your code
We suggest you format your code again using the same tool and parameters as in Step 1.
Step 6. Commit
Review the changes in your repository and commit them to your new branch. Do not merge yet, you're not done!
Step 7. Remove any reference to Metalama
At this point, your code base no longer requires processing by the Metalama compiler — the metalama divorce command has already set MetalamaEnabled to false in every .csproj. However, your code base still contains references to the Metalama libraries. Removing them is tedious but straightforward.
Currently, Metalama doesn't provide a way to automatically remove fabrics and aspect custom attributes from your code. Therefore, we recommend:
- Editing all aspects to turn them into plain custom attributes,
- Removing all fabrics,
- Removing Metalama NuGet package references from your projects.
PowerShell script
The steps above, except the last one, are summarized in the following script.
# Run git status and capture the output
$gitStatus = $(git status --porcelain)
# Check if the repo has uncommitted changes
if (-not [string]::IsNullOrWhiteSpace($gitStatus)) {
throw "Uncommitted changes detected. Please commit or stash your changes."
}
# Create a new branch
$currentTimestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$branchName = "divorce-$currentTimestamp"
git checkout -b $branchName
# Format code
dotnet format
# Commit
git commit -a -m "Formatting the code before Metalama divorce."
# Clean obj/bin to avoid stale transformed files
Get-ChildItem -Path . -Recurse -Force -Directory |
Where-Object { $_.Name -in 'obj', 'bin' } |
Remove-Item -Recurse -Force
# Build with transformed-files output
$env:MetalamaEmitCompilerTransformedFiles = "true"
$env:MetalamaFormatOutput = "true"
dotnet build /t:rebuild
Remove-Item Env:MetalamaEmitCompilerTransformedFiles -ErrorAction SilentlyContinue
Remove-Item Env:MetalamaFormatOutput -ErrorAction SilentlyContinue
# Write generated code back to the source code
metalama divorce
# Format
dotnet format
# Commit the divorce
git commit -a -m "Metalama divorce: inject transformed code."
# Verify the build succeeds with the stock compiler
dotnet build /t:rebuild