Skip to content

Instantly share code, notes, and snippets.

@chrisfcarroll
Created April 30, 2025 14:48
Show Gist options
  • Save chrisfcarroll/36b38f0cfed2800edaae790b2bd759d5 to your computer and use it in GitHub Desktop.
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.
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(); }
}
}
/// <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