Created
April 30, 2025 14:48
-
-
Save chrisfcarroll/36b38f0cfed2800edaae790b2bd759d5 to your computer and use it in GitHub Desktop.
DotNet C# DisposableArray<T>, DisposableList<T>. Simplify creating and disposing an array or list of disposable elements by having the container be disposable.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
/// <summary> | |
/// A <see cref="IDisposable"/> wrapper for a <see cref="T[]"/> which, when it is disposed, | |
/// disposes each of its non-null elements. | |
/// </summary> | |
public class DisposableArray<T> : Array<T>, IDisposable where T : IDisposable | |
{ | |
public DisposableArray(IEnumerable<T> items):base(items){} | |
public DisposableArray(int size):base(size){} | |
public void Dispose() | |
{ | |
List<Exception> exceptions = new(); | |
foreach (var item in array) | |
{ | |
try { item?.Dispose(); } | |
catch (Exception e) { exceptions.Add(e); } | |
} | |
if (exceptions.Count == 1) throw exceptions[0]; | |
if (exceptions.Any()) throw new AggregateException(exceptions); | |
} | |
} | |
public interface IArray<T> | |
{ | |
public T this[int index] { get ; set ; } | |
int Length { get; } | |
long LongLength { get; } | |
int Rank { get; } | |
object SyncRoot { get; } | |
bool IsReadOnly { get; } | |
bool IsFixedSize { get; } | |
bool IsSynchronized { get; } | |
int MaxLength { get; } | |
// Methods | |
void CopyTo(Array target, int index); | |
void CopyTo(Array target, long index); | |
IEnumerator GetEnumerator(); | |
int GetLength(int dimension); | |
long GetLongLength(int dimension); | |
int GetLowerBound(int dimension); | |
int GetUpperBound(int dimension); | |
object? GetValue(params int[] indices); | |
object? GetValue(params long[] indices); | |
void SetValue(object value, params int[] indices); | |
void SetValue(object value, params long[] indices); | |
void Initialize(); | |
/// <summary>Initiaze this[index] to <c>initializeFunction(index)</c></summary> | |
public void Initialize(Func<int,T> initializeFunction); | |
/// <summary>Initiaze each item to <c>initializeFunction()</c></summary> | |
public void Initialize(Func<T> initializeFunction); | |
/// <summary>Initiaze each item to <c>initialValue</c></summary> | |
public void Initialize(T initialValue); | |
/// <summary>Initiaze each item to <c>initialValue.Clone()</c></summary> | |
/// <param name="initialValue">after cloning, this must also be castable to <typeparamref name="T"/></param> | |
public void InitializeByCloning(ICloneable initialValue); | |
} | |
public class Array<T> : IArray<T> | |
{ | |
public T this[int index] | |
{ | |
get => array[index]; | |
set => array[index] = value; | |
} | |
protected readonly T[] array; | |
public Array(int size) => array = new T[size]; | |
public Array(IEnumerable<T> enumerable) => array = enumerable.ToArray(); | |
public int Length => array.Length; | |
public long LongLength => array.LongLength; | |
public int Rank => array.Rank; | |
public object SyncRoot => array.SyncRoot; | |
public bool IsReadOnly => array.IsReadOnly; | |
public bool IsFixedSize => array.IsFixedSize; | |
public bool IsSynchronized => array.IsSynchronized; | |
public int MaxLength => Array.MaxLength; | |
public void CopyTo(Array target,int index) => array.CopyTo(target,index); | |
public void CopyTo(Array target,long index) => array.CopyTo(target,index); | |
public IEnumerator GetEnumerator() => array.GetEnumerator(); | |
public int GetLength(int dimension) => array.GetLength(dimension); | |
public long GetLongLength(int dimension) => array.GetLongLength(dimension); | |
public int GetLowerBound(int dimension) => array.GetLowerBound(dimension); | |
public int GetUpperBound(int dimension) => array.GetUpperBound(dimension); | |
public object? GetValue(params int[] indices) => array.GetValue(indices); | |
public object? GetValue(params long[] indices) => array.GetValue(indices); | |
public void SetValue(object value,params int[] indices) => array.SetValue(value,indices); | |
public void SetValue(object value,params long[] indices) => array.SetValue(value,indices); | |
public void Initialize() => array.Initialize(); | |
public void Initialize(Func<int,T> initializeFunction) | |
{ | |
for (int i = 0; i < array.Length; i++) { array[i] = initializeFunction(i); } | |
} | |
public void Initialize(Func<T> initializeFunction) | |
{ | |
for (int i = 0; i < array.Length; i++) { array[i] = initializeFunction(); } | |
} | |
public void Initialize(T initialValue) | |
{ | |
for (int i = 0; i < array.Length; i++) { array[i] = initialValue; } | |
} | |
public void InitializeByCloning(ICloneable initialValue) | |
{ | |
for (int i = 0; i < array.Length; i++) { array[i] = (T)initialValue.Clone(); } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// A <see cref="IDisposable"/> <see cref="List{T}"/> which, when it is disposed, | |
/// disposes each of its non-null elements | |
/// </summary> | |
public class DisposableList<T> : List<T>, IDisposable where T : IDisposable | |
{ | |
public void Dispose() | |
{ | |
List<Exception> exceptions = new(); | |
foreach (var item in this) | |
{ | |
try { item?.Dispose(); } | |
catch (Exception e) { exceptions.Add(e); } | |
} | |
if (exceptions.Count == 1) throw exceptions[0]; | |
if (exceptions.Any()) throw new AggregateException(exceptions); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment