From 87bd4234dfd985f661828ad542cb618c8776fbf4 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 10:28:13 +0300 Subject: [PATCH 1/3] Initial commit with task details for issue #23 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/linksplatform/Disposables/issues/23 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a2f0f2c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/Disposables/issues/23 +Your prepared branch: issue-23-7cdd2a3c +Your prepared working directory: /tmp/gh-issue-solver-1757834890964 + +Proceed. \ No newline at end of file From d6e514c9cbf7a79ec1348e32d4eed7fc0f7a6ab2 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 10:37:14 +0300 Subject: [PATCH 2/3] Add factory methods and extension methods for wrapping System.IDisposable objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Disposable.Create(IDisposable) static factory method - Add Disposable.Create(IDisposable) static factory method - Add Disposable.Create((IDisposable, IDisposable)) static factory method - Add AsDisposable() extension method for wrapping IDisposable in Disposable - Add AsDisposableContainer() extension method for wrapping IDisposable in Disposable - Add comprehensive unit tests for all new functionality Fixes #23 - Think about implicit converters from other Disposables and IDisposable objects (to implement wrappers) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../DisposableTests.cs | 103 ++++++++++++++++++ csharp/Platform.Disposables/Disposable.cs | 8 ++ .../Disposable[TPrimary, TAuxiliary].cs | 8 ++ csharp/Platform.Disposables/Disposable[T].cs | 8 ++ .../IDisposableExtensions.cs | 18 +++ 5 files changed, 145 insertions(+) diff --git a/csharp/Platform.Disposables.Tests/DisposableTests.cs b/csharp/Platform.Disposables.Tests/DisposableTests.cs index caa19fb..0f9e804 100644 --- a/csharp/Platform.Disposables.Tests/DisposableTests.cs +++ b/csharp/Platform.Disposables.Tests/DisposableTests.cs @@ -79,5 +79,108 @@ private static string GetDisposalObjectTestProjectFilePath() } return path; } + + [Fact] + public static void WrapSystemIDisposableInDisposableTest() + { + var disposed = false; + var testDisposable = new TestDisposable(() => disposed = true); + + // Test creating wrapper from System.IDisposable using Create method + var wrapper = Disposable.Create(testDisposable); + Assert.NotNull(wrapper); + Assert.False(disposed); + + wrapper.Dispose(); + Assert.True(disposed); + } + + [Fact] + public static void WrapSystemIDisposableInGenericDisposableTest() + { + var disposed = false; + var testDisposable = new TestDisposable(() => disposed = true); + + // Test creating generic wrapper from System.IDisposable using Create method + var wrapper = Disposable.Create(testDisposable); + Assert.NotNull(wrapper); + Assert.Same(testDisposable, wrapper.Object); + Assert.False(disposed); + + wrapper.Dispose(); + Assert.True(disposed); + } + + [Fact] + public static void WrapTwoSystemIDisposableInDisposableTest() + { + var disposed1 = false; + var disposed2 = false; + var testDisposable1 = new TestDisposable(() => disposed1 = true); + var testDisposable2 = new TestDisposable(() => disposed2 = true); + + // Test creating wrapper for two System.IDisposable objects using Create method + var wrapper = Disposable.Create((testDisposable1, testDisposable2)); + Assert.NotNull(wrapper); + Assert.Same(testDisposable1, wrapper.Object); + Assert.Same(testDisposable2, wrapper.AuxiliaryObject); + Assert.False(disposed1); + Assert.False(disposed2); + + wrapper.Dispose(); + Assert.True(disposed1); + Assert.True(disposed2); + } + + [Fact] + public static void AsDisposableExtensionMethodTest() + { + var disposed = false; + var testDisposable = new TestDisposable(() => disposed = true); + + // Test extension method that wraps System.IDisposable in Disposable + var wrapper = testDisposable.AsDisposable(); + Assert.NotNull(wrapper); + Assert.False(disposed); + + wrapper.Dispose(); + Assert.True(disposed); + } + + [Fact] + public static void AsDisposableContainerExtensionMethodTest() + { + var disposed = false; + var testDisposable = new TestDisposable(() => disposed = true); + + // Test extension method that wraps System.IDisposable in Disposable + var wrapper = testDisposable.AsDisposableContainer(); + Assert.NotNull(wrapper); + Assert.Same(testDisposable, wrapper.Object); + Assert.False(disposed); + + wrapper.Dispose(); + Assert.True(disposed); + } + + private class TestDisposable : System.IDisposable + { + private readonly Action _disposeAction; + private bool _disposed = false; + + public TestDisposable(Action disposeAction) + { + _disposeAction = disposeAction ?? throw new ArgumentNullException(nameof(disposeAction)); + } + + public void Dispose() + { + if (!_disposed) + { + _disposed = true; + _disposeAction(); + } + } + } } } diff --git a/csharp/Platform.Disposables/Disposable.cs b/csharp/Platform.Disposables/Disposable.cs index 9d0c028..0b77aa9 100644 --- a/csharp/Platform.Disposables/Disposable.cs +++ b/csharp/Platform.Disposables/Disposable.cs @@ -65,6 +65,14 @@ public Disposable(Action action) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Disposable(Disposal disposal) => new Disposable(disposal); + /// + /// Creates a new object that wraps the specified object. + /// Создает новый объект , который оборачивает указанный объект . + /// + /// The object to wrap.Объект для оборачивания. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Disposable Create(System.IDisposable disposable) => new Disposable(() => disposable?.Dispose()); + /// /// Disposes unmanaged resources. /// Высвобождает неуправляемые ресурсы. diff --git a/csharp/Platform.Disposables/Disposable[TPrimary, TAuxiliary].cs b/csharp/Platform.Disposables/Disposable[TPrimary, TAuxiliary].cs index 3fde638..5cd400b 100644 --- a/csharp/Platform.Disposables/Disposable[TPrimary, TAuxiliary].cs +++ b/csharp/Platform.Disposables/Disposable[TPrimary, TAuxiliary].cs @@ -111,6 +111,14 @@ public Disposable(TPrimary @object) : base(@object) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Disposable(ValueTuple tuple) => new Disposable(tuple.Item1, tuple.Item2); + /// + /// Creates a new object that wraps two objects and calls their Dispose methods when disposed. + /// Создает новый объект , который оборачивает два объекта и вызывает их методы Dispose при высвобождении. + /// + /// The tuple containing two objects to wrap.Кортеж, содержащий два объекта для оборачивания. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Disposable Create(ValueTuple disposables) => new Disposable(disposables.Item1, disposables.Item2, (obj1, obj2) => { obj1?.Dispose(); obj2?.Dispose(); }); + /// /// Creates a new copy of the primary object (). /// Создаёт новую копию основного объекта (). diff --git a/csharp/Platform.Disposables/Disposable[T].cs b/csharp/Platform.Disposables/Disposable[T].cs index e9f0790..2ce6863 100644 --- a/csharp/Platform.Disposables/Disposable[T].cs +++ b/csharp/Platform.Disposables/Disposable[T].cs @@ -96,6 +96,14 @@ public Disposable(T @object, Action action) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Disposable(T @object) => new Disposable(@object); + /// + /// Creates a new object that wraps the specified object and calls its Dispose method when disposed. + /// Создает новый объект , который оборачивает указанный объект и вызывает его метод Dispose при высвобождении. + /// + /// The object to wrap.Объект для оборачивания. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static new Disposable Create(System.IDisposable disposable) => new Disposable(disposable, obj => obj?.Dispose()); + /// /// Creates a new copy of the primary object (). /// Создаёт новую копию основного объекта (). diff --git a/csharp/Platform.Disposables/IDisposableExtensions.cs b/csharp/Platform.Disposables/IDisposableExtensions.cs index 3cff9b6..0a5afe7 100644 --- a/csharp/Platform.Disposables/IDisposableExtensions.cs +++ b/csharp/Platform.Disposables/IDisposableExtensions.cs @@ -21,5 +21,23 @@ public static void DisposeIfNotDisposed(this IDisposable disposable) disposable.Dispose(); } } + + /// + /// Wraps a object in a wrapper. + /// Оборачивает объект в обёртку . + /// + /// The object to wrap.Объект для оборачивания. + /// A new wrapper.Новая обёртка . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Disposable AsDisposable(this System.IDisposable disposable) => Disposable.Create(disposable); + + /// + /// Wraps a object in a wrapper. + /// Оборачивает объект в обёртку . + /// + /// The object to wrap.Объект для оборачивания. + /// A new wrapper.Новая обёртка . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Disposable AsDisposableContainer(this System.IDisposable disposable) => Disposable.Create(disposable); } } From 8943ed9a905c246fb3dec0ab81bf27ce21cc9a14 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 10:37:39 +0300 Subject: [PATCH 3/3] Remove CLAUDE.md - Claude command completed --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index a2f0f2c..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/Disposables/issues/23 -Your prepared branch: issue-23-7cdd2a3c -Your prepared working directory: /tmp/gh-issue-solver-1757834890964 - -Proceed. \ No newline at end of file