首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ArrayPoolWrapper简洁、安全的ArrayPool

ArrayPoolWrapper简洁、安全的ArrayPool

原创
作者头像
雪飞鸿
发布2026-04-29 09:17:02
发布2026-04-29 09:17:02
160
举报
文章被收录于专栏:me的随笔me的随笔

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

ArrayPool本身的使用方式比较简单:

代码语言:c#
复制
using System.Buffers;

var pool = ArrayPool<int>.Shared.Rent(4);
// 其他逻辑
ArrayPool<int>.Shared.Return(pool);

为了确保在发生异常时能够释放资源,通常需要写成如下形式的样板代码:

代码语言:c#
复制
int[] pool = null!;
try
{
    pool = ArrayPool<int>.Shared.Rent(4);
    // 其他逻辑
}
finally
{
    if (pool != null)
    {
        ArrayPool<int>.Shared.Return(pool);
    }
}

以上写法会是我们的代码中充斥大量的样板代码和大量的嵌套,影响代码后续的可读性和可维护性。

接下来我们在原ArrayPool的基础上稍加封装,以实现简洁、安全的使用ArrayPool的目标,封装后的使用只需一行代码,效果如下:

代码语言:c#
复制
using var pool = new ArrayPoolWrapper<int>(5);

具体实现代码如下:

代码语言:c#
复制
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>));
        }
    }
}

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

代码语言:c#
复制
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--;
    }
}

使用示例如下:

代码语言:c#
复制
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上开源。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档