mirror of
https://github.com/oliverbooth/X10D
synced 2024-11-09 23:45:42 +00:00
Add DisposeAll(Async) and ClearAndDisposeAll(Async)
This commit is contained in:
parent
7b8c344ddd
commit
adf2281f21
76
X10D.Tests/src/Collections/CollectionTests.cs
Normal file
76
X10D.Tests/src/Collections/CollectionTests.cs
Normal file
@ -0,0 +1,76 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using X10D.Collections;
|
||||
|
||||
namespace X10D.Tests.Collections;
|
||||
|
||||
[TestClass]
|
||||
public class CollectionTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ClearAndDisposeAll_ShouldDispose_GivenCollection()
|
||||
{
|
||||
var collection = new List<Disposable> {new(), new(), new()};
|
||||
var copy = new List<Disposable>(collection);
|
||||
|
||||
collection.ClearAndDisposeAll();
|
||||
|
||||
Assert.IsTrue(copy.All(x => x.IsDisposed));
|
||||
Assert.AreEqual(0, collection.Count);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task ClearAndDisposeAllAsync_ShouldDispose_GivenCollection()
|
||||
{
|
||||
var collection = new List<Disposable> {new(), new(), new()};
|
||||
var copy = new List<Disposable>(collection);
|
||||
|
||||
await collection.ClearAndDisposeAllAsync();
|
||||
|
||||
Assert.IsTrue(copy.All(x => x.IsDisposed));
|
||||
Assert.AreEqual(0, collection.Count);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ClearAndDisposeAll_ShouldThrow_GivenNull()
|
||||
{
|
||||
List<Disposable>? collection = null;
|
||||
Assert.ThrowsException<ArgumentNullException>(() => collection!.ClearAndDisposeAll());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ClearAndDisposeAllAsync_ShouldThrow_GivenNull()
|
||||
{
|
||||
List<Disposable>? collection = null;
|
||||
Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await collection!.ClearAndDisposeAllAsync());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ClearAndDisposeAll_ShouldThrow_GivenReadOnlyCollection()
|
||||
{
|
||||
var collection = new List<Disposable>().AsReadOnly();
|
||||
Assert.ThrowsException<InvalidOperationException>(() => collection.ClearAndDisposeAll());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ClearAndDisposeAllAsync_ShouldThrow_GivenReadOnlyCollection()
|
||||
{
|
||||
var collection = new List<Disposable>().AsReadOnly();
|
||||
Assert.ThrowsExceptionAsync<InvalidOperationException>(async () => await collection.ClearAndDisposeAllAsync());
|
||||
}
|
||||
|
||||
private class Disposable : IDisposable, IAsyncDisposable
|
||||
{
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Assert.IsTrue(IsDisposed = true);
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
Assert.IsTrue(IsDisposed = true);
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using X10D.Collections;
|
||||
|
||||
namespace X10D.Tests.Collections;
|
||||
@ -6,6 +6,36 @@ namespace X10D.Tests.Collections;
|
||||
[TestClass]
|
||||
public class EnumerableTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void DisposeAll_ShouldDispose_GivenCollection()
|
||||
{
|
||||
var collection = new List<Disposable> {new(), new(), new()};
|
||||
collection.DisposeAll();
|
||||
Assert.IsTrue(collection.All(x => x.IsDisposed));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task DisposeAllAsync_ShouldDispose_GivenCollection()
|
||||
{
|
||||
var collection = new List<Disposable> {new(), new(), new()};
|
||||
await collection.DisposeAllAsync();
|
||||
Assert.IsTrue(collection.All(x => x.IsDisposed));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DisposeAll_ShouldThrow_GivenNull()
|
||||
{
|
||||
List<Disposable>? collection = null;
|
||||
Assert.ThrowsException<ArgumentNullException>(() => collection!.DisposeAll());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task DisposeAllAsync_ShouldThrow_GivenNull()
|
||||
{
|
||||
List<Disposable>? collection = null;
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await collection!.DisposeAllAsync());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void For_ShouldTransform_GivenTransformationDelegate()
|
||||
{
|
||||
@ -86,4 +116,20 @@ public class EnumerableTests
|
||||
{
|
||||
public int Value { get; set; }
|
||||
}
|
||||
|
||||
private class Disposable : IDisposable, IAsyncDisposable
|
||||
{
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Assert.IsTrue(IsDisposed = true);
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
Assert.IsTrue(IsDisposed = true);
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
77
X10D/src/Collections/CollectionExtensions.cs
Normal file
77
X10D/src/Collections/CollectionExtensions.cs
Normal file
@ -0,0 +1,77 @@
|
||||
namespace X10D.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Collection-related extension methods for <see cref="ICollection{T}" />.
|
||||
/// </summary>
|
||||
public static class CollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Calls <see cref="IDisposable.Dispose" /> on each item in the collection, then clears the collection by calling
|
||||
/// <see cref="ICollection{T}.Clear" />.
|
||||
/// </summary>
|
||||
/// <param name="source">The collection to clear, and whose elements should be disposed.</param>
|
||||
/// <typeparam name="T">The type of the elements in <paramref name="source" />.</typeparam>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="source" /> is <see langword="null" />.</exception>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="source" /> is read-only.</exception>
|
||||
/// <seealso cref="EnumerableExtensions.DisposeAll{T}" />
|
||||
public static void ClearAndDisposeAll<T>(this ICollection<T> source) where T : IDisposable
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
if (source.IsReadOnly)
|
||||
{
|
||||
throw new InvalidOperationException("Collection is read-only. Try using DisposeAll instead.");
|
||||
}
|
||||
|
||||
foreach (T item in source)
|
||||
{
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
if (item is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.Dispose();
|
||||
}
|
||||
|
||||
source.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously calls <see cref="IAsyncDisposable.DisposeAsync" /> on each item in the collection, then clears the
|
||||
/// collection by calling <see cref="ICollection{T}.Clear" />.
|
||||
/// </summary>
|
||||
/// <param name="source">The collection to clear, and whose elements should be disposed.</param>
|
||||
/// <typeparam name="T">The type of the elements in <paramref name="source" />.</typeparam>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="source" /> is <see langword="null" />.</exception>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="source" /> is read-only.</exception>
|
||||
/// <seealso cref="EnumerableExtensions.DisposeAllAsync{T}" />
|
||||
public static async Task ClearAndDisposeAllAsync<T>(this ICollection<T> source) where T : IAsyncDisposable
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
if (source.IsReadOnly)
|
||||
{
|
||||
throw new InvalidOperationException("Collection is read-only. Try using DisposeAllAsync instead.");
|
||||
}
|
||||
|
||||
foreach (T item in source)
|
||||
{
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
if (item is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await item.DisposeAsync();
|
||||
}
|
||||
|
||||
source.Clear();
|
||||
}
|
||||
}
|
@ -75,6 +75,59 @@ public static class EnumerableExtensions
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls <see cref="IDisposable.Dispose" /> on all elements of the <see cref="IEnumerable{T}" />.
|
||||
/// </summary>
|
||||
/// <param name="source">The enumerable collection whose elements to dispose.</param>
|
||||
/// <typeparam name="T">The type of the elements in <paramref name="source" />.</typeparam>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="source" /> is <see langword="null" />.</exception>
|
||||
/// <seealso cref="CollectionExtensions.ClearAndDisposeAll{T}" />
|
||||
public static void DisposeAll<T>(this IEnumerable<T> source) where T : IDisposable
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
foreach (T item in source)
|
||||
{
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
if (item is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously calls <see cref="IAsyncDisposable.DisposeAsync" /> on all elements of the
|
||||
/// <see cref="IEnumerable{T}" />.
|
||||
/// </summary>
|
||||
/// <param name="source">The enumerable collection whose elements to dispose.</param>
|
||||
/// <typeparam name="T">The type of the elements in <paramref name="source" />.</typeparam>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="source" /> is <see langword="null" />.</exception>
|
||||
/// <seealso cref="CollectionExtensions.ClearAndDisposeAllAsync{T}" />
|
||||
public static async Task DisposeAllAsync<T>(this IEnumerable<T> source) where T : IAsyncDisposable
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
foreach (T item in source)
|
||||
{
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
if (item is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await item.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reorganizes the elements in an enumerable by implementing a Fisher-Yates shuffle, and returns th shuffled result.
|
||||
/// </summary>
|
||||
|
Loading…
Reference in New Issue
Block a user