< Summary

Information
Class: NexusLabs.Needlr.AgentFramework.Progress.CompositeDisposable
Assembly: NexusLabs.Needlr.AgentFramework
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework/Progress/CompositeDisposable.cs
Line coverage
80%
Covered lines: 17
Uncovered lines: 4
Coverable lines: 21
Total lines: 66
Line coverage: 80.9%
Branch coverage
100%
Covered branches: 10
Total branches: 10
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
.ctor(...)100%11100%
Dispose()100%1010100%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework/Progress/CompositeDisposable.cs

#LineLine coverage
 1namespace NexusLabs.Needlr.AgentFramework.Progress;
 2
 3/// <summary>
 4/// Composite <see cref="IDisposable"/> that owns a fixed set of child disposables
 5/// and releases them in reverse order on <see cref="Dispose"/>.
 6/// </summary>
 7/// <remarks>
 8/// <para>
 9/// Null entries are ignored, allowing callers to mix typed references with
 10/// conditional <c>as IDisposable</c> casts without pre-filtering. All entries
 11/// are disposed even if earlier ones throw; collected exceptions are re-thrown
 12/// as a single <see cref="AggregateException"/>.
 13/// </para>
 14/// <para>
 15/// Used primarily by the source generator's <c>BeginXxxAgentProgressScope</c>
 16/// emission to tie the lifetime of per-scope sinks (that implement
 17/// <see cref="IDisposable"/>) to the returned scope handle, preventing leaks.
 18/// </para>
 19/// </remarks>
 20public sealed class CompositeDisposable : IDisposable
 21{
 22    private readonly IDisposable?[] _disposables;
 23    private bool _disposed;
 24
 25    /// <summary>
 26    /// Creates a composite wrapping the supplied disposables in order.
 27    /// </summary>
 028    public CompositeDisposable(IEnumerable<IDisposable?> disposables)
 29    {
 030        ArgumentNullException.ThrowIfNull(disposables);
 031        _disposables = disposables.ToArray();
 032    }
 33
 34    /// <summary>
 35    /// Creates a composite wrapping the supplied disposables in order.
 36    /// </summary>
 437    public CompositeDisposable(params IDisposable?[] disposables)
 38    {
 439        ArgumentNullException.ThrowIfNull(disposables);
 440        _disposables = disposables;
 441    }
 42
 43    /// <inheritdoc />
 44    public void Dispose()
 45    {
 646        if (_disposed) return;
 447        _disposed = true;
 48
 449        List<Exception>? errors = null;
 2850        for (int i = _disposables.Length - 1; i >= 0; i--)
 51        {
 52            try
 53            {
 1054                _disposables[i]?.Dispose();
 955            }
 156            catch (Exception ex)
 57            {
 158                errors ??= new List<Exception>();
 159                errors.Add(ex);
 160            }
 61        }
 62
 463        if (errors is not null)
 164            throw new AggregateException(errors);
 365    }
 66}