Implement the dispose pattern using SourceGenerator.
Use this like below.
using IDisposableSourceGenerator;
[IDisposableGenerator]
partial class Foo { } // must be partial classThen the boilerplate code for the disposable pattern will be generated.
partial class Foo : System.IDisposable
{
protected readonly SimpleCompositeDisposable _disposables =
new SimpleCompositeDisposable();
private bool _disposedValue;
protected virtual void Dispose(bool disposing)
{
if (_disposedValue) return;
if (disposing)
{
// TODO: called on disposing the managed objects.
//OnDisposing();
// TODO: dispose managed state (managed objects).
_disposables.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
//DisposeUnmanagedObjects();
// TODO: set large fields to null.
//SetLargeFieldsToNull();
_disposedValue = true;
}
//~Foo() => Dispose(disposing: false);
public void Dispose()
{
Dispose(disposing: true);
System.GC.SuppressFinalize(this);
}
}Generator declare a _disposables field of SimpleCompositeDisposable type . You can add disposable objects with it.
The field name _disposables can be changed with a generator argument. see CompositeDisposableFieldName.
[IDisposableGenerator]
partial class Foo {
public Foo(IDisposable d) {
_disposables.Add(d); // d will be automatically disposed.
}
}You can specify the type of CompositeDisposable.
If you don't specified or set default, the default class IDisposableSourceGenerator.SimpleCompositeDisposable in the source generator is used.
[IDisposableGenerator(typeof(System.Reactive.Disposables.CompositeDisposable))]
partial class Foo {
public Foo(IDisposable d) {
_disposables.Add(d); // GetType() == typeof(System.Reactive.Disposables.CompositeDisposable)
}
}You can change the name of CompositeDisposable field.
If filed name is default or whitespace, it named _disposables.
using IDisposableSourceGenerator;
[IDisposableGenerator(default, "myAwesomeDisposables")] // CompositeDisposable type is default.
partial class Foo {
public Foo(IDisposable d) {
myAwesomeDisposables.Add(d); // The name specified in the argument.
}
}Generator generates the IDisposableGeneratorOptions that has bit flags of which method to implement.
[Flags]
internal enum IDisposableGeneratorOptions {
None = 0x0000,
DisposeUnmanagedObjectsMethod = 0x0001,
SetLargeFieldsToNullMethod = 0x0002,
OnDisposingMethod = 0x0004,
}Of course, each option can be set simultaneously.
[IDisposableGenerator(default, default, IDisposableGeneratorOptions.DisposeUnmanagedObjectsMethod | IDisposableGeneratorOptions.SetLargeFieldsToNullMethod | IDisposableGeneratorOptions.OnDisposingMethod)]
partial class Foo {
...
}If you want to release some unmanaged objects, you can use the IDisposableGeneratorOptions.DisposeUnmanagedObjectsMethod flag.
This option enables the DisposeUnmanagedObjects method and Finalizer. It will be called from the Dispose method or Finalizer.
[IDisposableGenerator(default, default, IDisposableGeneratorOptions.DisposeUnmanagedObjectsMethod)]
partial class Foo {
protected virtual partial void DisposeUnmanagedObjects()
{
// release some unmanaged objects in this.
}
}If you want to set some large fields to null, you can use the IDisposableGeneratorOptions.SetLargeFieldsToNullMethod flag.
This option enables the SetLargeFieldsToNull method and Finalizer. It will be called from the Dispose method or Finalizer.
[IDisposableGenerator(default, default, IDisposableGeneratorOptions.SetLargeFieldsToNullMethod)]
partial class Foo {
protected virtual partial void SetLargeFieldsToNull()
{
// set some large fields to null in this.
}
}If you want to do something when disposing the managed objects, you can use the IDisposableGeneratorOptions.OnDisposing flag.
This option enables the OnDisposing method. It will be called before disposed CompositeDisposables from the Dispose method.
[IDisposableGenerator(default, default, IDisposableGeneratorOptions.OnDisposingMethod)]
partial class Foo {
protected virtual partial void OnDisposing()
{
// do something when disposing
}
}Maybe WPF app requires editing the *.csproj file.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<!-- for WPF, add the following settings -->
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IDisposableSourceGenerator" Version="1.0.0" >
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>This library is under the MIT License.
本プロジェクトでは以下を参考にさせて頂きました。素晴らしいソフトウェアを公開してくださり感謝いたします。