ArrayPoolWrapper简洁、安全的ArrayPool
通过.NET中的
ArrayPool本身的使用方式比较简单:
using System.Buffers; var pool = ArrayPool<int>.Shared.Rent(4); // 其他逻辑 ArrayPool<int>.Shared.Return(pool);
为了确保在发生异常时能够释放资源,通常需要写成如下形式的样板代码:
int[] pool = null!; try { pool = ArrayPool<int>.Shared.Rent(4); // 其他逻辑 } finally { if (pool != null) { ArrayPool<int>.Shared.Return(pool); } }
以上写法会是我们的代码中充斥大量的样板代码和大量的嵌套,影响代码后续的可读性和可维护性。
接下来我们在原ArrayPool的基础上稍加封装,以实现简洁、安全的使用ArrayPool的目标,代码如下:
public struct ArrayPoolWrapper: IDisposable { private int _index = -1; private bool _disposed = false; private readonly int _capacity; private readonly T[] _pool; public ArrayPoolWrapper(int capacity) { if (capacity <= 0) { throw new ArgumentOutOfRangeException(nameof(capacity), "The capacity must be greater than 0."); } this._capacity = capacity; _pool = ArrayPool .Shared.Rent(capacity); } public void Add(T info) { ThrowIfDisposed(); _index++; if (_index >= _capacity) { _index--; throw new InvalidOperationException("The array pool has reached its capacity."); } _pool[_index] = info; } public void Dispose() { ThrowIfDisposed(); _disposed = true; ArrayPool .Shared.Return(_pool); } private readonly void ThrowIfDisposed() { if (_disposed) { throw new ObjectDisposedException(nameof(ArrayPoolWrapper )); } } }
封装后的使用只需一行代码,效果如下:
using var pool = new ArrayPoolWrapper<int>(5);
我们还可以通过封装来实现更多的扩展API,如:RemoveLastOne以及基于Span的切片操作:
public struct ArrayPoolWrapper: IDisposable { public readonly int Count => _index + 1; public readonly Span Values => _pool.AsSpan()[..Count]; public void RemoveLastOne() { ThrowIfDisposed(); if (Count <= 0) { throw new InvalidOperationException("The array pool is empty."); } _pool[_index] = default!; _index--; } }
使用示例如下:
using var pool = new ArrayPoolWrapper<int>(8); for (var i = 0; i < 8; i++) { pool.Add(i); } pool.RemoveLastOne(); Console.WriteLine(pool.Count); foreach (var i in pool.Values[1..3]) { Console.WriteLine(i); }
完整的实现代码已在
原文地址: https://www.cveoy.top/t/topic/qGxj 著作权归作者所有。请勿转载和采集!