IAsyncDisposableインターフェイスは.NET Standard 2.1/.NET Core 3.0以降で提供されるインターフェイスで、IDisposableインターフェイスの非同期版です。 IDisposableインターフェイスのDisposeメソッドと同様、DisposeAsyncメソッドが用意されており、このインターフェイスを実装することにより非同期の破棄・解放処理を行うための操作を提供することができるようになります。
IAsyncDisposableインターフェイスはIDisposableインターフェイスとともに実装することも、単独で実装することもできます。 つまり、同期的な破棄・解放処理と、非同期的な破棄・解放処理のどちらかのみ、あるいは両方を実装することができます。 ただし、両方を実装する場合は、どちらか一方で破棄・解放処理が行われたら、もう一方が呼び出されても二重に破棄・解放が行われないように実装する必要があります。
IDisposableインターフェイスはusingステートメントとともに使用することができるのと同様、IAsyncDisposableインターフェイスは非同期版のawait usingステートメントとともに使用することができます。
IAsyncDisposableは、主にStream等のIAsyncDisposableインターフェイスを実装するクラスを内包して扱うようなクラスを作成する際に実装することが多くなるものと思われます。
以下は、IAsyncDisposableを実装し、クラス内で保持しているStreamを非同期的に破棄できるようにする例です。
あくまでIAsyncDisposableインターフェイスのみを主眼においた実装となっているため、例外時等の考慮は十分ではない点に注意してください。 より適切な実装については§.ファイナライザとIDisposableのデザインパターン (disposeパターン)を参照してください。
using System;
using System.IO;
using System.Threading.Tasks;
// IAsyncDisposableインターフェイスを実装するクラス
class Resource : IAsyncDisposable {
private Stream stream; // 解放すべきリソースとしてStreamを内包する
public Resource()
{
// なんらかのStreamインスタンスを作成することを想定(ここでは代替としてStream.Nullを使用)
this.stream = Stream.Null;
}
public async ValueTask DisposeAsync()
{
if (stream == null)
return; // すでに解放済みの場合は何もしない
// DisposeAsyncメソッドで解放する
await stream.DisposeAsync().ConfigureAwait(false);
// 解放済みであることを示すためにnullを設定する
stream = null;
}
}
class Sample {
static async Task Main()
{
var res1 = new Resource();
// DisposeAsyncメソッドを呼び出す
await res1.DisposeAsync();
// await usingステートメントを使用する場合は次のようになる
await using (var res2 = new Resource()) {
} // スコープから抜ける時点でDisposeAsyncメソッドが呼び出される
}
}
VB16時点のVisual Basicでは、ValueTaskを返すAsync Functionがサポートされていない?(コンパイルエラーとなる)ため、IAsyncDisposableインターフェイスは実装できないようです。
Imports System
Imports System.IO
Imports System.Threading.Tasks
' IAsyncDisposableインターフェイスを実装するクラス
Class Resource
Implements IAsyncDisposable
Private stream As Stream ' 解放すべきリソースとしてStreamを内包する
Public Sub New()
' なんらかのStreamインスタンスを作成することを想定(ここでは代替としてStream.Nullを使用)
Me.stream = Stream.Null
End Sub
Public Async Function DisposeAsync() As ValueTask ' error BC36945: Async' 修飾子は、Sub と、Task または Task(Of T) を返す Function でのみ使用できます。
If stream Is Nothing Then Return ' すでに解放済みの場合は何もしない
' DisposeAsyncメソッドで解放する
Await stream.DisposeAsync().ConfigureAwait(False)
' 解放済みであることを示すためにNothingを設定する
stream = Nothing
End Function
End Class
Class Sample
Shared Async Function Main() As Task
Dim res1 As New Resource()
' DisposeAsyncメソッドを呼び出す
Await res1.DisposeAsync()
' VB16時点ではC# 8.0のawait usingに相当する構文は用意されていない
' await using (var res2 = new Resource()) {
' }
End Function
End Class