Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions PowerKit.Tests/DisposableTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using FluentAssertions;
using Xunit;

Expand All @@ -21,6 +22,22 @@ public void Create_Test()
invoked.Should().BeTrue();
}

[Fact]
public void Create_Idempotent_Test()
{
// Arrange
var count = 0;
var disposable = Disposable.Create(() => Interlocked.Increment(ref count));

// Act
disposable.Dispose();
disposable.Dispose();
disposable.Dispose();

// Assert
count.Should().Be(1);
}

[Fact]
public void Merge_Test()
{
Expand Down
10 changes: 9 additions & 1 deletion PowerKit/Disposable.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
using System;
using System.Collections.Generic;
using System.Threading;

namespace PowerKit;

file class DelegateDisposable(Action dispose) : IDisposable
{
public void Dispose() => dispose();
private Action? _dispose = dispose;

public void Dispose() =>
// Idempotency
Interlocked.Exchange(ref _dispose, null)?.Invoke();
}

/// <summary>
Expand All @@ -21,6 +26,9 @@ public static class Disposable
/// <summary>
/// Creates a disposable that invokes the specified action when disposed.
/// </summary>
/// <remarks>
/// The returned disposable is idempotent and invokes the action at most once.
/// </remarks>
public static IDisposable Create(Action dispose) => new DelegateDisposable(dispose);

/// <summary>
Expand Down