ArrayPoolWrapper简洁、安全的ArrayPool

通过.NET中的 ArrayPool 我们可以实现对T[]类型的池化,避免频繁的分配内存和GC,以提升性能。鉴于已有不少博客介绍ArrayPool的具体原理,本文不会涉及其实现细节。本文聚焦使用中的痛点,并提供简洁的封装方案以提升ArrarPool使用的便捷性。

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<T> : 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<T>.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<T>.Shared.Return(_pool);
    }
​
​
    private readonly void ThrowIfDisposed()
    {
        if (_disposed)
        {
            throw new ObjectDisposedException(nameof(ArrayPoolWrapper<T>));
        }
    }
}

封装后的使用只需一行代码,效果如下:

复制代码
using var pool = new ArrayPoolWrapper<int>(5);

我们还可以通过封装来实现更多的扩展API,如:RemoveLastOne以及基于Span的切片操作:

复制代码
public struct ArrayPoolWrapper<T> : IDisposable
{
    public readonly int Count => _index + 1;
    public readonly Span<T> 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);
} 

完整的实现代码已在Github上开源。

相关推荐
叫我少年11 小时前
C#基础数据类型
c#·数据类型
唐青枫12 小时前
C#.NET YARP 跨域配置详解:网关统一处理 CORS
c#·.net
程序leo源14 小时前
Qt信号与槽深度详解
c语言·开发语言·数据库·c++·qt·c#
yoyo_zzm19 小时前
四大编程语言对比:C/C++/C#/PHP
c++·c#·php
weixin_4280053020 小时前
C#调用 AI学习从0开始-第1阶段(基础与工具)-第4天CoT思维链学习
开发语言·学习·ai·c#·cot
政沅同学20 小时前
C# TCP通讯(客户端)
网络·tcp/ip·c#
思麟呀21 小时前
在C++基础上理解CSharp-3
开发语言·c++·c#
rockey6271 天前
AScript如何实现LINQ语法
sql·c#·.net·linq·script·eval·expression
xiaoshuaishuai81 天前
C# CDN加速与离线包优化PowerSetting慢问题
开发语言·windows·spring·c#
烈焰猩猩1 天前
【无标题】
c#