Skip to main content

Dirge by Kazuki Kohzuki

NuGet / site data

Nuget GitHub last commit GitHub Repo stars

Details

Info

info

Name: Dirge

Disposable Implementation Roslyn Generator Extension

Author: Kazuki Kohzuki

NuGet: https://www.nuget.org/packages/Dirge/

You can find more details at https://github.com/IkuzakIkuzok/Dirge

Source: https://github.com/IkuzakIkuzok/Dirge

Author

note

Kazuki Kohzuki Alt text

Original Readme

note

Dirge

Test Version Download MIT License

Disposable Implementation Roslyn Generator Extension

Installation

You can install the EnumSerializer from NuGet.

Usage

Mark a class with the [AutoDispose] attribute and implement the IDisposable interface. The generator will automatically generate the implementation of the Dispose method for you.

using Dirge;

namespace Test;

[AutoDispose]
internal partial class TestClass
{
private readonly Stream _stream = new MemoryStream();
}

The generated code will look like this:

namespace Test;

partial class TestClass : IDisposable
{
private bool __generated_disposed = false;

public void Dispose()
{
Dispose(true);
global::System.GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (this.__generated_disposed) return;

try
{
if (disposing)
{
this._stream?.Dispose();
}
}
finally
{
this.__generated_disposed = true;
}
}
}

Note that this example is simplified for demonstration purposes.

To suppress the auto-generated Dispose call for a specific field, you can use the [DoNotDispose] attribute:

using Dirge;

namespace Test;

[AutoDispose]
internal partial class TestClass
{
private readonly Stream _stream1 = new MemoryStream();

[DoNotDispose]
private readonly Stream _stream2 = new MemoryStream(); // This field will not be disposed by the generated Dispose method.
}

Ref-struct is also supported, but IDisposable will not be implemented regardless of the language version.

######### Conditional disposal

Conditional disposal, which allows you to specify conditions under which a field should be disposed, is also supported. You can use the [DoNotDisposeWhen] attribute with a boolean field and a value to compare against:

using Dirge;

namespace Test;

[AutoDispose]
internal partial class TestClass
{
private readonly bool _leaveOpen;

[DoNotDisposeWhen(nameof(_leaveOpen), true)]
private readonly Stream _stream;

internal TestClass(Stream stream, bool leaveOpen)
{
this._stream = stream;
this._leaveOpen = leaveOpen;
}
}

This will prevent the generator from disposing the _stream field when the _leaveOpen field is true:

namespace Test;

partial class TestClass : IDisposable
{
private bool __generated_disposed = false;

public void Dispose()
{
Dispose(true);
global::System.GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (this.__generated_disposed) return;

try
{
if (disposing)
{
if (!this._leaveOpen)
{
this._stream?.Dispose();
}
}
}
finally
{
this.__generated_disposed = true;
}
}
}

######### Unmanaged resources

To safely release unmanaged resources, this generator also supports the implementation of a finalizer. You can specify a method to release unmanaged resources through the ReleaseUnmanagedResources option:

using Dirge;
using System.IO;

namespace Test;

[AutoDispose(ReleaseUnmanagedResources = nameof(ReleaseUnmanagedResources))]
internal sealed partial class TestClass
{
private readonly Stream _stream;

internal void ReleaseUnmanagedResources()
{
// Custom logic to release unmanaged resources
}
}

This will generate a finalizer that calls the specified method to release unmanaged resources:

namespace Test;

sealed partial class TestClass : IDisposable
{
private bool __generated_disposed = false;

public void Dispose()
{
Dispose(true);
global::System.GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if (this.__generated_disposed) return;

try
{
if (disposing)
{
this._stream?.Dispose();
}

ReleaseUnmanagedResources();
}
finally
{
this.__generated_disposed = true;
}
}

~TestClass()
{
Dispose(false);
}
}
Constraints

To generate the Dispose method, the class (or struct) must meet the following constraints:

  • It must be a non-static class.
  • It must be a partial class or struct.
  • It must not be a readonly struct.

For conditional disposal, the field specified in the nameof expression must be a boolean field. Properties and methods are not supported for the current version.

About

note

Dirge is a Roslyn-based code generator that automatically implements the IDisposable pattern for C# classes.

Key Features:

  1. AutoDispose Attribute: Mark any partial class with [AutoDispose] to automatically generate Dispose() and Dispose(bool) methods.

  2. Automatic Field Disposal: The generator detects all disposable fields and automatically calls .Dispose() on them in the correct order.

How to use

Example (source csproj, source files)

This is the CSharp Project that references Dirge

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dirge" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>

Generated Files

Those are taken from $(BaseIntermediateOutputPath)\GX

// <auto-generated/>

#pragma warning disable CS0282

namespace IDisposableGeneratorDemo
{
partial class DALDB : global::System.IDisposable
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
[global::System.Diagnostics.DebuggerBrowsable(global::System.Diagnostics.DebuggerBrowsableState.Never)]
[global::System.Runtime.CompilerServices.CompilerGenerated]
private bool __generated_disposed = false;

public void Dispose()
{
Dispose(true);
global::System.GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (this.__generated_disposed) return;

try
{
if (disposing)
{
this.cn?.Dispose();
this.cn1?.Dispose();
}
}
finally
{
this.__generated_disposed = true;
}
}
}
}

Useful

Download Example (.NET C#)

Share Dirge

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Dirge

Category "Disposer" has the following generators:

1 BenutomoAutomaticDisposeImplSourceGenerator Nuget GitHub Repo stars 2023-08-15

2 Coplt.Dropping Nuget GitHub Repo stars 2024-08-13

3 Dirge Nuget GitHub Repo stars 2026-07-01

4 DisposableHelpers Nuget GitHub Repo stars 2023-10-09

5 Disposer Nuget GitHub Repo stars 2023-10-03

6 GenerateDispose Nuget GitHub Repo stars 2026-05-13

7 IDisposableGenerator Nuget GitHub Repo stars 2023-10-11

See category

Disposer