Skip to content

About

Roslyn analyzers and code fixes for modern .NET performance patterns. Flags allocations, virtual dispatch, and boxing on hot paths — with multi-TFM awareness.

Topics

Resources

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Latest commit

 

History

177 Commits

Folders and files

Repository files navigation

ZeroAlloc.Analyzers

NuGet Build codecov License: MIT AOT GitHub Sponsors

Roslyn analyzers that catch allocations and NativeAOT breakers at compile time: 64 rules for the performance patterns the built-in .NET analyzers miss, each silenced automatically where your target framework can't use the fix.

Why ZeroAlloc.Analyzers

  • Find allocations in the build, not in a profiler. Boxing in string concatenation, LINQ in loops, double dictionary lookups, closures, uncached delegates and missed FrozenDictionary opportunities show up as warnings where you write the code.
  • Catch NativeAOT breakers early. The ZA17xx rules flag Expression.Compile, Reflection.Emit, reflection-based serializers, dynamic and assembly-scanning registration before a trimmed or AOT publish fails.
  • Every diagnostic is actionable. Rules that need .NET 5, 6, 7, 8 or 9, or a newer C# version, are silenced on older targets, so you never see a fix for an API you can't call.
  • A few percent of build time. On a 240-file sample, a median of +2.1% for a full net8.0 build and +2.9% for a one-file edit; a build with no changes runs no analyzers at all.

Install

dotnet add package ZeroAlloc.Analyzers

It is a development dependency: nothing flows to your consumers, and there is no runtime assembly.

Quick start

Build, and the diagnostics appear in dotnet build, Visual Studio, Rider and VS Code with C# Dev Kit:

public sealed class PriceCache
{
    private readonly Dictionary<string, decimal> _prices = new();

    public decimal Get(string sku)
    {
        // warning ZA0105: Use 'TryGetValue' instead of 'ContainsKey' followed by indexer access
        if (_prices.ContainsKey(sku))
            return _prices[sku];
        return 0m;
    }
}

Apply the code fix from the lightbulb, or with dotnet format, and the two lookups become one:

        if (_prices.TryGetValue(sku, out var value))
            return value;

What you get

Performance

Build overhead on a 240-file, 18,000-line sample, relative to the same project built without the package; median of 15 interleaved pairs.

Target Full build One-file edit
net8.0 +2.1% +2.9%
net8.0 + netstandard2.0 +4.3% +5.4%
netstandard2.0 +10.5% +23.0%

A build with no changes does not run the compiler, so the analyzers add no work. The overhead is largest on netstandard2.0, where the SDK's own analyzers don't run and the build is smaller.

How many rules run per target, the spread, the environment, the harness to reproduce it and tips for fast local builds: docs/performance.md.

Learn more

About

Roslyn analyzers and code fixes for modern .NET performance patterns. Flags allocations, virtual dispatch, and boxing on hot paths — with multi-TFM awareness.

Topics

Resources

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages