てくメモ

trivial な notes

【C#】遠慮なく IDisposable な構造体で包んで using

IDisposableな構造体について。

アロケーションを避けるために構造体を使用したとしても、IDisposableインターフェースが噛む using ではbox化が発生するのでは――?
との疑問も浮かぶが、具象で using するケースでは発生しない。(devirtualization? 違うかも)

参考:
structをusing-statementで使用したらboxingが発生するのか - えんじにあ雑記!


構造体なら処理ひとつを包むのに使うハードルが低い。
というわけで包むぞ!


後処理を考えると少し不格好になってしまうような、例としてArrayPoolを考える。

// const int SIZE;
byte[]? buf = null;
try
{
    buf = ArrayPool<byte>.Shared.Rent(SIZE);
    // 処理
}
finally
{
    if (buf is not null) ArrayPool<byte>.Shared.Return(buf);
}

リソース後処理の try~finally は普通だけれど、using IDisposableの見た目になれると少しぎこちなく見えてしまう。


そこで、ラッパーを考えてみる。

internal readonly struct ArrayPoolWrapper<T> : IDisposable
{
    public readonly int Length;
    private readonly T[] array;

    public ArrayPoolWrapper(int length)
    {
        Length = length;
        array = ArrayPool<T>.Shared.Rent(length);
    }
    
    public Memory<T> AsMemory() => array.AsMemory(0, Length);
    public Span<T> AsSpan() => array.AsSpan(0, Length);

    public void Dispose() => ArrayPool<T>.Shared.Return(array);
}
using ArrayPoolWrapper<byte> buf = new(SIZE);
// Span や Memory を通して処理


個人的にはやはり、try~finally より using の方が馴染む。