Josupeit.Practices.Mixins.Disposable 1.0.12

Prefix Reserved
dotnet add package Josupeit.Practices.Mixins.Disposable --version 1.0.12
                    
NuGet\Install-Package Josupeit.Practices.Mixins.Disposable -Version 1.0.12
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Josupeit.Practices.Mixins.Disposable" Version="1.0.12">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Josupeit.Practices.Mixins.Disposable" Version="1.0.12" />
                    
Directory.Packages.props
<PackageReference Include="Josupeit.Practices.Mixins.Disposable">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Josupeit.Practices.Mixins.Disposable --version 1.0.12
                    
#r "nuget: Josupeit.Practices.Mixins.Disposable, 1.0.12"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Josupeit.Practices.Mixins.Disposable@1.0.12
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Josupeit.Practices.Mixins.Disposable&version=1.0.12
                    
Install as a Cake Addin
#tool nuget:?package=Josupeit.Practices.Mixins.Disposable&version=1.0.12
                    
Install as a Cake Tool

Josupeit.Practices.Mixins.Disposable

Implementing IDisposable correctly is not hard in principle — check whether you have already disposed, release managed resources, release unmanaged resources, suppress finalization — but it is repetitive, and the repetition creates opportunities for subtle bugs: forgetting the idempotency check, not implementing IAsyncDisposable alongside IDisposable, or calling the wrong overload. When you have dozens of classes that own resources, that boilerplate adds up fast.

This meta-package installs a Roslyn source generator that writes the entire dispose implementation for you. You mark a class with [DisposableMixin], provide methods for the resources you actually own, and the generator produces a correct, idiomatic dispose pattern at compile time — no runtime overhead, no reflection.

dotnet add package Josupeit.Practices.Mixins.Disposable

The package is marked as a development dependency (DevelopmentDependency=true), so it does not appear as a runtime dependency in packages that consume your library.

How to use

Mark your class as partial and apply [DisposableMixin]. Then provide override points for the resource categories you own. You do not need to implement IDisposable or IAsyncDisposable yourself — the generator adds them.

using Josupeit.Practices.Mixins.Disposable;

[DisposableMixin]
public partial class DataExporter
{
    private readonly Stream _output = File.Create("export.bin");

    public async Task ExportAsync(IEnumerable<Record> records, CancellationToken cancellationToken)
    {
        ThrowIfDisposed(); // generated guard — call this at the start of every public method
        await WriteRecordsAsync(_output, records, cancellationToken);
    }

    // Override this if you own managed (disposable) resources.
    protected virtual void DisposeManagedResources()
    {
        _output.Dispose();
    }

    // Override this if you own managed resources that support async disposal.
    protected virtual async ValueTask DisposeManagedResourcesAsync()
    {
        await _output.DisposeAsync();
    }

    // Override this if you own unmanaged resources (handles, pointers, etc.).
    // protected virtual void DisposeUnmanagedResources() { ... }
}

The generator produces both IDisposable and IAsyncDisposable implementations by default on platforms that support it (netstandard2.1 and later). This mirrors the behavior of the BCL's own disposable types and avoids the awkwardness of implementing only one interface when callers might need the other.

Options

Pass a DisposableMixinOptions flags value to the attribute to tailor the generated code.

Flag Effect
WithProperty Generates a public bool IsDisposed { get; } property
WithEvent Generates a Disposing event that is raised when the instance is about to release its resources
WithoutIdempotencyGuarantees Omits the double-dispose guard — use only when you can guarantee Dispose is called once
WithoutAsyncDisposable Generates only IDisposable, not IAsyncDisposable
// Expose disposal state for UI binding or observability.
[DisposableMixin(DisposableMixinOptions.WithProperty | DisposableMixinOptions.WithEvent)]
public partial class ObservableConnection { … }

Generated marker attributes

The generator emits DisposableMixinAttribute and DisposableMixinOptions into every consuming compilation, so the package needs no runtime assembly at all. Alongside them it emits a declaration of Microsoft.CodeAnalysis.EmbeddedAttribute, which is what keeps those two types out of your assembly's public metadata - even for projects you have granted InternalsVisibleTo. Embedding is a metadata import filter rather than an accessibility check, so consumers of your library cannot name the mixin's attributes at all.

That declaration is deliberately bare - no AttributeUsage, no Conditional, no GeneratedCode, no self-application. All of those are AllowMultiple = false, and the type is partial, so any of them would merge with another generator's half of the same declaration and produce error CS0579: Duplicate 'AttributeUsage' attribute. Keeping it bare lets the mixin coexist with PolySharp, with Roslyn's own synthesized declaration, and with any other generator that declares the type.

Opting out

Two preprocessor symbols suppress parts of that output.

Symbol Effect
JOSUPEIT_PRACTICES_MIXINS_DISPOSABLE_NO_ATTRIBUTES Emits nothing at all - no EmbeddedAttribute, no DisposableMixinAttribute, no DisposableMixinOptions
JOSUPEIT_PRACTICES_MIXINS_DISPOSABLE_NO_EMBEDDED_ATTRIBUTE Omits only the EmbeddedAttribute declaration, keeping the mixin's own attributes
<PropertyGroup>
  <DefineConstants>$(DefineConstants);JOSUPEIT_PRACTICES_MIXINS_DISPOSABLE_NO_EMBEDDED_ATTRIBUTE</DefineConstants>
</PropertyGroup>

Reach for the second symbol when a co-generator emits a non-partial EmbeddedAttribute, so merging is not an option, or when you simply want to own that declaration yourself. Note that the mixin's attributes still carry [Embedded], so you have to supply an EmbeddedAttribute of your own - otherwise the generated code fails with error CS0234: The type or namespace name 'CodeAnalysis' does not exist in the namespace 'Microsoft'. A bare declaration is enough:

namespace Microsoft.CodeAnalysis
{
    internal sealed partial class EmbeddedAttribute : global::System.Attribute
    {
    }
}

Defining JOSUPEIT_PRACTICES_MIXINS_DISPOSABLE_NO_ATTRIBUTES implies the second symbol, so projects that already use it are unaffected. With it defined you have to hand-declare the entire attribute contract yourself, which the generator matches by full type name (Josupeit.Practices.Mixins.Disposable.DisposableMixinAttribute).

Analyzer and code fixes

The package also includes a Roslyn analyzer that catches common mistakes at compile time — for example, forgetting the partial keyword, using the wrong visibility on a cleanup method, or applying the mixin to a class that already inherits a disposable base. Most of these diagnostics come with a code fix you can apply directly from the IDE's lightbulb menu. The code fixes can also scaffold the DisposeManagedResources, DisposeManagedResourcesAsync, and DisposeUnmanagedResources method stubs for you.

For the full list of diagnostics and code fixes, see the Analyzer README.

For the complete generated member reference and generator limitations, see the Generator README.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.12 0 8/21/2026
1.0.9 140 3/30/2026
1.0.7 121 3/10/2026

- Pins package resolution with lock files and locked restore on CI
- Fixes the disposable mixin colliding with a foreign EmbeddedAttribute