ReflectionIT.DisposeGenerator
0.2.0-preview
Prefix Reserved
See the version list below for details.
dotnet add package ReflectionIT.DisposeGenerator --version 0.2.0-preview
NuGet\Install-Package ReflectionIT.DisposeGenerator -Version 0.2.0-preview
<PackageReference Include="ReflectionIT.DisposeGenerator" Version="0.2.0-preview" />
<PackageVersion Include="ReflectionIT.DisposeGenerator" Version="0.2.0-preview" />
<PackageReference Include="ReflectionIT.DisposeGenerator" />
paket add ReflectionIT.DisposeGenerator --version 0.2.0-preview
#r "nuget: ReflectionIT.DisposeGenerator, 0.2.0-preview"
#:package ReflectionIT.DisposeGenerator@0.2.0-preview
#addin nuget:?package=ReflectionIT.DisposeGenerator&version=0.2.0-preview&prerelease
#tool nuget:?package=ReflectionIT.DisposeGenerator&version=0.2.0-preview&prerelease
ReflectionIT.DisposeGenerator
A source generator package that implements the Dispose pattern.
- https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern
- https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose
Planned future support includes the async dispose pattern.
https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync
NuGet package
| Package | Version |
|---|---|
| ReflectionIT.DisposeGenerator |
Usage
Install the NuGet package, then annotate a class or struct with the Disposable attribute.
Annotate properties or fields with the Dispose attribute. Use SetToNull when the property or field holds a large object and should be set to null after disposal.
using ReflectionIT.DisposeGenerator.Attributes;
[Disposable]
public partial class LogWriter : IDisposable {
[Dispose(SetToNull = true)]
private StreamWriter StreamWriter { get; set; }
public LogWriter(string path) => StreamWriter = new StreamWriter(path);
public void WriteLine(string text) => StreamWriter.WriteLine($"{DateTime.Now}\t{text}");
}
This generates the following partial class, which disposes the StreamWriter property and sets it to null.
partial class LogWriter
{
public void Dispose() {
Dispose(disposing: true);
global::System.GC.SuppressFinalize(this);
}
private bool _isDisposed;
protected virtual void Dispose(bool disposing) {
if (!_isDisposed) {
if (disposing) {
StreamWriter?.Dispose();
}
StreamWriter = null;
_isDisposed = true;
}
}
}
Implement the dispose pattern for a derived class
A class derived from a class that already implements IDisposable should not implement IDisposable again, because the base implementation of IDisposable.Dispose is inherited by derived classes.
Set the OverrideDispose property of the Disposable attribute to true. In that case, the public parameterless Dispose method is not generated, and the protected Dispose(bool) method is generated as an override instead.
[Disposable(OverrideDispose = true)]
public partial class SecondLogWriter : LogWriter {
[Dispose]
private StreamWriter SecondStreamWriter { get; }
public SecondLogWriter(string path) : base(path) => SecondStreamWriter = new StreamWriter(path + "2");
public override void WriteLine(string text) {
base.WriteLine(text);
SecondStreamWriter.WriteLine($"{DateTime.Now}\t{text.ToUpper()}");
}
}
This generates the following partial class, which disposes the SecondStreamWriter property.
partial class SecondLogWriter
{
private bool _isDisposed;
protected override void Dispose(bool disposing) {
if (!_isDisposed) {
if (disposing) {
SecondStreamWriter?.Dispose();
}
_isDisposed = true;
}
base.Dispose(disposing);
}
}
Unmanaged resources
You can also release unmanaged resources. Set the HasUnmanagedResources property of the Disposable attribute to true.
Then implement the partial method ReleaseUnmanagedResources, which releases the unmanaged resource.
If you need to work with unmanaged resources, we strongly recommend wrapping the unmanaged IntPtr handle in a SafeHandle.
[Disposable(HasUnmanagedResources = true)]
public partial class LogWriterWithAnExtraIntPtr : IDisposable {
private readonly IntPtr _pointer;
[Dispose]
private StreamWriter StreamWriter { get; }
public LogWriterWithAnExtraIntPtr(string path) {
StreamWriter = new StreamWriter(path);
_pointer = Marshal.AllocHGlobal(cb: 128);
}
public void WriteLine(string text) => StreamWriter.WriteLine($"{DateTime.Now}\t{text}");
// Implement this partial method to release the unmanaged resources.
protected virtual partial void ReleaseUnmanagedResources() => Marshal.FreeHGlobal(_pointer);
}
This generates the following partial class with a finalizer and a partial method named ReleaseUnmanagedResources that you must implement.
partial class LogWriterWithAnExtraIntPtr
{
public void Dispose() {
Dispose(disposing: true);
global::System.GC.SuppressFinalize(this);
}
~LogWriterWithAnExtraIntPtr() {
Dispose(disposing: false);
}
protected virtual partial void ReleaseUnmanagedResources();
private bool _isDisposed;
protected virtual void Dispose(bool disposing) {
if (!_isDisposed) {
if (disposing) {
StreamWriter?.Dispose();
}
ReleaseUnmanagedResources();
_isDisposed = true;
}
}
}
Thread-safe disposal
Use Interlocked.CompareExchange to ensure thread-safe disposal. Set the IsThreadSafe property of the Disposable attribute to true.
[Disposable(IsThreadSafe = true)]
public partial class LogWriter : IDisposable {
[Dispose]
private readonly StreamWriter _streamWriter;
public LogWriter(string path) => _streamWriter = new StreamWriter(path);
public void WriteLine(string text) => _streamWriter.WriteLine($"{DateTime.Now}\t{text}");
}
This generates the following partial class, which uses Interlocked.CompareExchange to ensure thread-safe disposal.
partial class LogWriter
{
public void Dispose() {
Dispose(disposing: true);
global::System.GC.SuppressFinalize(this);
}
private int _isDisposed;
protected virtual void Dispose(bool disposing) {
if (global::System.Threading.Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0) {
if (disposing) {
_streamWriter?.Dispose();
}
}
}
}
License
This project is licensed under the MIT License. See the LICENSE file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.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 |
|---|---|---|
| 0.4.2-preview | 50 | 6/12/2026 |
| 0.4.1-preview | 55 | 6/4/2026 |
| 0.4.0-preview | 60 | 4/29/2026 |
| 0.3.0-preview | 59 | 4/28/2026 |
| 0.2.0-preview | 60 | 4/20/2026 |
| 0.1.0-preview | 55 | 4/20/2026 |
Introduced HasUnmanagedResources property to DisposableAttribute and updated the source generator to handle finalizers and ReleaseUnmanagedResources partial methods.
Introduced ExplicitInterfaceImplementation property to DisposableAttribute class and updated the source generator to implement the IDisposable interface explicitly.