From d21df465cd50b1e94540578c14676fe9fcd414ec Mon Sep 17 00:00:00 2001 From: Nikolay Pianikov Date: Fri, 26 Apr 2024 19:36:38 +0300 Subject: [PATCH] Improved code-generation for Dispose and DisposeAsync --- readme/Avalonia.md | 2 +- readme/BlazorServerApp.md | 2 +- readme/BlazorWebAssemblyApp.md | 2 +- readme/Console.md | 2 +- readme/ConsoleNativeAOT.md | 2 +- readme/ConsoleTopLevelStatements.md | 2 +- readme/GrpcService.md | 2 +- readme/Maui.md | 2 +- readme/MinimalWebAPI.md | 2 +- readme/WebAPI.md | 2 +- readme/WebApp.md | 2 +- readme/WinFormsApp.md | 2 +- readme/WinFormsAppNetCore.md | 2 +- readme/Wpf.md | 2 +- readme/async-disposable-scope.md | 39 ++--------- readme/async-disposable-singleton.md | 39 ++--------- readme/disposable-singleton.md | 39 +++++++---- readme/scope.md | 39 +++++++---- readme/service-provider-with-scope.md | 40 +++++++---- .../Core/Code/DisposeMethodBuilder.cs | 69 +++++++++++-------- 20 files changed, 137 insertions(+), 156 deletions(-) diff --git a/readme/Avalonia.md b/readme/Avalonia.md index 1c3f363c4..9cbae20f0 100644 --- a/readme/Avalonia.md +++ b/readme/Avalonia.md @@ -107,7 +107,7 @@ The [project file](/samples/AvaloniaApp/AvaloniaApp.csproj) looks like this: - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/BlazorServerApp.md b/readme/BlazorServerApp.md index 5d8e6f5ff..6a40a17d9 100644 --- a/readme/BlazorServerApp.md +++ b/readme/BlazorServerApp.md @@ -68,7 +68,7 @@ The [project file](/samples/BlazorServerApp/BlazorServerApp.csproj) looks like t - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/BlazorWebAssemblyApp.md b/readme/BlazorWebAssemblyApp.md index c66cf3e78..0140f1a90 100644 --- a/readme/BlazorWebAssemblyApp.md +++ b/readme/BlazorWebAssemblyApp.md @@ -67,7 +67,7 @@ The [project file](/samples/BlazorWebAssemblyApp/BlazorWebAssemblyApp.csproj) lo - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/Console.md b/readme/Console.md index df16b3b76..4485ce540 100644 --- a/readme/Console.md +++ b/readme/Console.md @@ -90,7 +90,7 @@ The [project file](/samples/ShroedingersCat/ShroedingersCat.csproj) looks like t - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/ConsoleNativeAOT.md b/readme/ConsoleNativeAOT.md index d3e834789..0079e986f 100644 --- a/readme/ConsoleNativeAOT.md +++ b/readme/ConsoleNativeAOT.md @@ -16,7 +16,7 @@ The [project file](/samples/ShroedingersCatNativeAOT/ShroedingersCatNativeAOT.cs - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/ConsoleTopLevelStatements.md b/readme/ConsoleTopLevelStatements.md index fc7f58481..9c92f19b6 100644 --- a/readme/ConsoleTopLevelStatements.md +++ b/readme/ConsoleTopLevelStatements.md @@ -78,7 +78,7 @@ The [project file](/samples/ShroedingersCatTopLevelStatements/ShroedingersCatTop - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/GrpcService.md b/readme/GrpcService.md index dc2503269..af8cbd451 100644 --- a/readme/GrpcService.md +++ b/readme/GrpcService.md @@ -53,7 +53,7 @@ The [project file](/samples/GrpcService/GrpcService.csproj) looks like this: - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/Maui.md b/readme/Maui.md index b06a37012..7cc5c597a 100644 --- a/readme/Maui.md +++ b/readme/Maui.md @@ -208,7 +208,7 @@ The [project file](/samples/MAUIApp/MAUIApp.csproj) looks like this: - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/MinimalWebAPI.md b/readme/MinimalWebAPI.md index 52c3d5648..28871ac0f 100644 --- a/readme/MinimalWebAPI.md +++ b/readme/MinimalWebAPI.md @@ -76,7 +76,7 @@ The [project file](/samples/WebAPI/WebAPI.csproj) looks like this: - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/WebAPI.md b/readme/WebAPI.md index 6d65c9fd3..38dc343d0 100644 --- a/readme/WebAPI.md +++ b/readme/WebAPI.md @@ -51,7 +51,7 @@ The [project file](/samples/WebAPI/WebAPI.csproj) looks like this: - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/WebApp.md b/readme/WebApp.md index b88698f4e..1338c0add 100644 --- a/readme/WebApp.md +++ b/readme/WebApp.md @@ -51,7 +51,7 @@ The [project file](/samples/WebApp/WebApp.csproj) looks like this: - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/WinFormsApp.md b/readme/WinFormsApp.md index 136b3f8bc..a26cfbbf3 100644 --- a/readme/WinFormsApp.md +++ b/readme/WinFormsApp.md @@ -55,7 +55,7 @@ The [project file](/samples/WinFormsApp/WinFormsApp.csproj) looks like this: - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/WinFormsAppNetCore.md b/readme/WinFormsAppNetCore.md index 2b4967619..697d8b268 100644 --- a/readme/WinFormsAppNetCore.md +++ b/readme/WinFormsAppNetCore.md @@ -62,7 +62,7 @@ The [project file](/samples/WinFormsAppNetCore/WinFormsAppNetCore.csproj) looks - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/Wpf.md b/readme/Wpf.md index d1d093223..3fe01b6e2 100644 --- a/readme/Wpf.md +++ b/readme/Wpf.md @@ -68,7 +68,7 @@ The [project file](/samples/WpfAppNetCore/WpfAppNetCore.csproj) looks like this: - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/readme/async-disposable-scope.md b/readme/async-disposable-scope.md index cc9bcb636..6e417dfb4 100644 --- a/readme/async-disposable-scope.md +++ b/readme/async-disposable-scope.md @@ -266,23 +266,9 @@ partial class Composition: global::System.IDisposable, global::System.IAsyncDisp _disposablesM04D26di = new object[1]; _scopedM04D26di36_Dependency = null; } - while (disposeIndex > 0) { var instance = disposables[--disposeIndex]; - var disposableInstance = instance as global::System.IDisposable; - if (disposableInstance != null) - { - try - { - disposableInstance.Dispose(); - } - catch (Exception exception) - { - OnDisposeException(disposableInstance, exception); - } - continue; - } var asyncDisposableInstance = instance as global::System.IAsyncDisposable; if (asyncDisposableInstance != null) @@ -299,11 +285,13 @@ partial class Composition: global::System.IDisposable, global::System.IAsyncDisp { OnAsyncDisposeException(asyncDisposableInstance, exception); } - continue; + continue; } } - } + + partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; + public async global::System.Threading.Tasks.ValueTask DisposeAsync() { int disposeIndex; @@ -316,11 +304,9 @@ partial class Composition: global::System.IDisposable, global::System.IAsyncDisp _disposablesM04D26di = new object[1]; _scopedM04D26di36_Dependency = null; } - while (disposeIndex > 0) { var instance = disposables[--disposeIndex]; - var asyncDisposableInstance = instance as global::System.IAsyncDisposable; if (asyncDisposableInstance != null) { @@ -332,28 +318,11 @@ partial class Composition: global::System.IDisposable, global::System.IAsyncDisp { OnAsyncDisposeException(asyncDisposableInstance, exception); } - continue; - } - var disposableInstance = instance as global::System.IDisposable; - if (disposableInstance != null) - { - try - { - disposableInstance.Dispose(); - } - catch (Exception exception) - { - OnDisposeException(disposableInstance, exception); - } continue; } } - } - partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; - - partial void OnAsyncDisposeException(T asyncDisposableInstance, Exception exception) where T : global::System.IAsyncDisposable; public override string ToString() diff --git a/readme/async-disposable-singleton.md b/readme/async-disposable-singleton.md index 7b26b308c..5bff14c81 100644 --- a/readme/async-disposable-singleton.md +++ b/readme/async-disposable-singleton.md @@ -201,23 +201,9 @@ partial class Composition: global::System.IDisposable, global::System.IAsyncDisp _disposablesM04D26di = new object[1]; _singletonM04D26di36_Dependency = null; } - while (disposeIndex > 0) { var instance = disposables[--disposeIndex]; - var disposableInstance = instance as global::System.IDisposable; - if (disposableInstance != null) - { - try - { - disposableInstance.Dispose(); - } - catch (Exception exception) - { - OnDisposeException(disposableInstance, exception); - } - continue; - } var asyncDisposableInstance = instance as global::System.IAsyncDisposable; if (asyncDisposableInstance != null) @@ -234,11 +220,13 @@ partial class Composition: global::System.IDisposable, global::System.IAsyncDisp { OnAsyncDisposeException(asyncDisposableInstance, exception); } - continue; + continue; } } - } + + partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; + public async global::System.Threading.Tasks.ValueTask DisposeAsync() { int disposeIndex; @@ -251,11 +239,9 @@ partial class Composition: global::System.IDisposable, global::System.IAsyncDisp _disposablesM04D26di = new object[1]; _singletonM04D26di36_Dependency = null; } - while (disposeIndex > 0) { var instance = disposables[--disposeIndex]; - var asyncDisposableInstance = instance as global::System.IAsyncDisposable; if (asyncDisposableInstance != null) { @@ -267,28 +253,11 @@ partial class Composition: global::System.IDisposable, global::System.IAsyncDisp { OnAsyncDisposeException(asyncDisposableInstance, exception); } - continue; - } - var disposableInstance = instance as global::System.IDisposable; - if (disposableInstance != null) - { - try - { - disposableInstance.Dispose(); - } - catch (Exception exception) - { - OnDisposeException(disposableInstance, exception); - } continue; } } - } - partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; - - partial void OnAsyncDisposeException(T asyncDisposableInstance, Exception exception) where T : global::System.IAsyncDisposable; public override string ToString() diff --git a/readme/disposable-singleton.md b/readme/disposable-singleton.md index af31b6728..25bec5daf 100644 --- a/readme/disposable-singleton.md +++ b/readme/disposable-singleton.md @@ -195,7 +195,6 @@ partial class Composition: global::System.IDisposable _disposablesM04D26di = new object[1]; _singletonM04D26di36_Dependency = null; } - while (disposeIndex > 0) { var instance = disposables[--disposeIndex]; @@ -212,31 +211,43 @@ partial class Composition: global::System.IDisposable } continue; } + } + } + + partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; + + public async global::System.Threading.Tasks.ValueTask DisposeAsync() + { + int disposeIndex; + object[] disposables; + lock (_lockM04D26di) + { + disposeIndex = _disposeIndexM04D26di; + _disposeIndexM04D26di = 0; + disposables = _disposablesM04D26di; + _disposablesM04D26di = new object[1]; + _singletonM04D26di36_Dependency = null; + } + while (disposeIndex > 0) + { + var instance = disposables[--disposeIndex]; - var asyncDisposableInstance = instance as global::System.IAsyncDisposable; - if (asyncDisposableInstance != null) + var disposableInstance = instance as global::System.IDisposable; + if (disposableInstance != null) { try { - var valueTask = asyncDisposableInstance.DisposeAsync(); - if (!valueTask.IsCompleted) - { - valueTask.AsTask().Wait(); - } + disposableInstance.Dispose(); } catch (Exception exception) { - OnAsyncDisposeException(asyncDisposableInstance, exception); + OnDisposeException(disposableInstance, exception); } - continue; + continue; } } - } - partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; - - partial void OnAsyncDisposeException(T asyncDisposableInstance, Exception exception) where T : global::System.IAsyncDisposable; public override string ToString() diff --git a/readme/scope.md b/readme/scope.md index 131748c8f..15f4a9c97 100644 --- a/readme/scope.md +++ b/readme/scope.md @@ -260,7 +260,6 @@ partial class Composition: global::System.IDisposable _disposablesM04D26di = new object[1]; _scopedM04D26di36_Dependency = null; } - while (disposeIndex > 0) { var instance = disposables[--disposeIndex]; @@ -277,31 +276,43 @@ partial class Composition: global::System.IDisposable } continue; } + } + } + + partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; + + public async global::System.Threading.Tasks.ValueTask DisposeAsync() + { + int disposeIndex; + object[] disposables; + lock (_lockM04D26di) + { + disposeIndex = _disposeIndexM04D26di; + _disposeIndexM04D26di = 0; + disposables = _disposablesM04D26di; + _disposablesM04D26di = new object[1]; + _scopedM04D26di36_Dependency = null; + } + while (disposeIndex > 0) + { + var instance = disposables[--disposeIndex]; - var asyncDisposableInstance = instance as global::System.IAsyncDisposable; - if (asyncDisposableInstance != null) + var disposableInstance = instance as global::System.IDisposable; + if (disposableInstance != null) { try { - var valueTask = asyncDisposableInstance.DisposeAsync(); - if (!valueTask.IsCompleted) - { - valueTask.AsTask().Wait(); - } + disposableInstance.Dispose(); } catch (Exception exception) { - OnAsyncDisposeException(asyncDisposableInstance, exception); + OnDisposeException(disposableInstance, exception); } - continue; + continue; } } - } - partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; - - partial void OnAsyncDisposeException(T asyncDisposableInstance, Exception exception) where T : global::System.IAsyncDisposable; public override string ToString() diff --git a/readme/service-provider-with-scope.md b/readme/service-provider-with-scope.md index e68da9c2a..121475a0a 100644 --- a/readme/service-provider-with-scope.md +++ b/readme/service-provider-with-scope.md @@ -250,7 +250,6 @@ partial class Composition: global::System.IDisposable _singletonM04D26di36_Dependency = null; _scopedM04D26di37_Service = null; } - while (disposeIndex > 0) { var instance = disposables[--disposeIndex]; @@ -267,31 +266,44 @@ partial class Composition: global::System.IDisposable } continue; } + } + } + + partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; + + public async global::System.Threading.Tasks.ValueTask DisposeAsync() + { + int disposeIndex; + object[] disposables; + lock (_lockM04D26di) + { + disposeIndex = _disposeIndexM04D26di; + _disposeIndexM04D26di = 0; + disposables = _disposablesM04D26di; + _disposablesM04D26di = new object[1]; + _singletonM04D26di36_Dependency = null; + _scopedM04D26di37_Service = null; + } + while (disposeIndex > 0) + { + var instance = disposables[--disposeIndex]; - var asyncDisposableInstance = instance as global::System.IAsyncDisposable; - if (asyncDisposableInstance != null) + var disposableInstance = instance as global::System.IDisposable; + if (disposableInstance != null) { try { - var valueTask = asyncDisposableInstance.DisposeAsync(); - if (!valueTask.IsCompleted) - { - valueTask.AsTask().Wait(); - } + disposableInstance.Dispose(); } catch (Exception exception) { - OnAsyncDisposeException(asyncDisposableInstance, exception); + OnDisposeException(disposableInstance, exception); } - continue; + continue; } } - } - partial void OnDisposeException(T disposableInstance, Exception exception) where T : global::System.IDisposable; - - partial void OnAsyncDisposeException(T asyncDisposableInstance, Exception exception) where T : global::System.IAsyncDisposable; public override string ToString() diff --git a/src/Pure.DI.Core/Core/Code/DisposeMethodBuilder.cs b/src/Pure.DI.Core/Core/Code/DisposeMethodBuilder.cs index ebe934a03..9d13c6e1e 100644 --- a/src/Pure.DI.Core/Core/Code/DisposeMethodBuilder.cs +++ b/src/Pure.DI.Core/Core/Code/DisposeMethodBuilder.cs @@ -19,6 +19,8 @@ public CompositionCode Build(CompositionCode composition) code.AppendLine(); } + var hasDisposable = composition.TotalDisposablesCount > composition.AsyncDisposableCount; + var hasAsyncDisposable = composition.AsyncDisposableCount > 0 && asyncDisposableSettings.IsEnabled(composition.Source.Source.SemanticModel.Compilation); var hints = composition.Source.Source.Hints; var isCommentsEnabled = hints.IsCommentsEnabled; if (isCommentsEnabled) @@ -33,25 +35,43 @@ public CompositionCode Build(CompositionCode composition) using (code.Indent()) { AddSyncPart(composition, code); - code.AppendLine("while (disposeIndex > 0)"); code.AppendLine("{"); using (code.Indent()) { code.AppendLine("var instance = disposables[--disposeIndex];"); - AddDisposePart(code); - AddAsyncDisposePart(composition, code, false); + if (hasDisposable) + { + AddDisposePart(code); + } + + if (hasAsyncDisposable) + { + code.AppendLine(); + AddAsyncDisposePart(composition, code, false); + } } code.AppendLine("}"); - code.AppendLine(); } code.AppendLine("}"); membersCounter++; - if (composition.AsyncDisposableCount > 0 && asyncDisposableSettings.IsEnabled(composition.Source.Source.SemanticModel.Compilation)) + code.AppendLine(); + code.AppendLine("/// "); + code.AppendLine("/// Implement this partial method to handle the exception on disposing."); + code.AppendLine("/// "); + code.AppendLine("/// The disposable instance."); + code.AppendLine("/// Exception occurring during disposal."); + code.AppendLine("/// The actual type of instance being disposed of."); + code.AppendLine($"partial void {Names.OnDisposeExceptionMethodName}(T disposableInstance, Exception exception) where T : {Names.IDisposableInterfaceName};"); + membersCounter++; + + // ReSharper disable once InvertIf + if (asyncDisposableSettings.IsEnabled(composition.Source.Source.SemanticModel.Compilation)) { + code.AppendLine(); if (isCommentsEnabled) { code.AppendLine("/// "); @@ -64,38 +84,29 @@ public CompositionCode Build(CompositionCode composition) using (code.Indent()) { AddSyncPart(composition, code); - code.AppendLine("while (disposeIndex > 0)"); code.AppendLine("{"); using (code.Indent()) { code.AppendLine("var instance = disposables[--disposeIndex];"); - AddAsyncDisposePart(composition, code, true); - AddDisposePart(code); + if (hasAsyncDisposable) + { + AddAsyncDisposePart(composition, code, true); + } + + if (hasDisposable) + { + code.AppendLine(); + AddDisposePart(code); + } } code.AppendLine("}"); - code.AppendLine(); } code.AppendLine("}"); membersCounter++; - } - - code.AppendLine(); - code.AppendLine("/// "); - code.AppendLine("/// Implement this partial method to handle the exception on disposing."); - code.AppendLine("/// "); - code.AppendLine("/// The disposable instance."); - code.AppendLine("/// Exception occurring during disposal."); - code.AppendLine("/// The actual type of instance being disposed of."); - code.AppendLine($"partial void {Names.OnDisposeExceptionMethodName}(T disposableInstance, Exception exception) where T : {Names.IDisposableInterfaceName};"); - code.AppendLine(); - membersCounter++; - - // ReSharper disable once InvertIf - if (asyncDisposableSettings.IsEnabled(composition.Source.Source.SemanticModel.Compilation)) - { + code.AppendLine(); code.AppendLine("/// "); code.AppendLine("/// Implement this partial method to handle the exception on async disposing."); @@ -107,7 +118,7 @@ public CompositionCode Build(CompositionCode composition) code.AppendLine(); membersCounter++; } - + return composition with { MembersCount = membersCounter }; } @@ -118,7 +129,6 @@ private void AddAsyncDisposePart(CompositionCode composition, LinesBuilder code, return; } - code.AppendLine(); code.AppendLine($"var asyncDisposableInstance = instance as {Names.IAsyncDisposableInterfaceName};"); code.AppendLine("if (asyncDisposableInstance != null)"); code.AppendLine("{"); @@ -154,9 +164,9 @@ private void AddAsyncDisposePart(CompositionCode composition, LinesBuilder code, } code.AppendLine("}"); + code.AppendLine("continue;"); } - - code.AppendLine("continue;"); + code.AppendLine("}"); } @@ -210,6 +220,5 @@ private static void AddSyncPart(CompositionCode composition, LinesBuilder code) } } code.AppendLine("}"); - code.AppendLine(); } } \ No newline at end of file