C# 8 – Освобождение ресурсов

C# logoСреди всех новых возможностей C# 8, две из них относятся к достаточно актуальной теме освобождения ресурсов. Теперь конструкция using может использоваться асинхронно и для части структур.

Асинхронное освобождение ресурсов (dispose)

C# 8 добавляет поддержку асинхронного освобождения ресурсов при помощи конструкции await using. Её использование аналогично обычному варианту using, но с поправкой на асинхронность:

await using (var x = new DisposableInstnace()) {
    …
}

При этом класс, экземпляр которого передается в это выражение, должен реализовывать IAsyncDisposable. Единственный метод этого интерфейса является ответственным за освобождение необходимых ресурсов:

public interface IAsyncDisposable
{
    ValueTask DisposeAsync();
}

Данный интерфейс используется для реализации другой новой возможности C# 8 – асинхронных потоков.

Поддержка освобождения ресурсов (dispose) для структур

Структуры, создаваемые только в стеке (ref struct) появились в C# 7.2. Они могут быть использованы для хранения неуправляемых или иных ресурсов, которые необходимо освободить как только они не будут нужны. Для класса в этом случае как правило используется конструкция using. Но для стуктур это не представляется возможным, так как они не поддерживают интерфейсы, а в данном случае требуется IDisposable.

C# 8 обходит это ограничение, используя “утиную типизацию”. Т.е. достаточно реализовать в структуре публичный метод void Dispose() и ее можно использовать в using.

Данная возможность применима к структурам объявленным как ref struct или readonly ref struct .

Пример:

internal ref struct Buffer<T>
{
    public readonly T[] Data;

    public Buffer(int size)
    {
        this.Data = ArrayPool<T>.Shared.Rent(size);
    }

    public void Dispose()
    {
        ArrayPool<T>.Shared.Return(this.Data, clearArray: true);
        Console.WriteLine("Dispose() called.");
    }
}

internal static class DisposableStructDemo
{
    public static void Run()
    {
        using (var b = new Buffer<int>(42)) {
            b.Data[0] = 42;
            Console.WriteLine($"Data = {b.Data[0]}");
        }
        
        Console.WriteLine("Method completed.");
    }
}

Добавить комментарий