はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#, Unity】JetBrains.Annotationsの[MustDisposeResource]はUniTaskにも対応してた話

はじめに

今回はJetBrains.Annotationsである[MustDisposeResource]について書きたいと思います。

github.com

これがTaskValueTaskには対応していても、UniTaskには対応していないのではという噂を聞いたのですが、それが本当か試してみました。

概要

[MustDisposeResource]を利用することでリソースの破棄を適切にしていないと警告を出すようにできます。

呼び出しコードで JetBrains.Annotations の [MustDisposeResourceAttribute] を使用して リソースの破棄を強制している場合、JetBrains Rider は、コンストラクターや破棄可能なリソースを返すファクトリメソッドで初期化された変数が適切に処理されていないケースを報告します。

破棄可能なリソースの誤った処理を避けるために、JetBrains Rider は変数宣言を using 宣言または using ブロックに変換することを提案します

コードインスペクション:[MustDisposeResource] アノテーションが付与されたメソッドの戻り値が破棄されていません | JetBrains Rider ドキュメント

// Warning: ローカル変数 'resource' は破棄されません
var resource = new Hoge(default);
        
// 警告なし
using var resource2 = new Hoge(default);


またRider 2024.1より非同期対応しまして、以下のようなTask<IDisposable>ValueTask<IDisposable>など非同期メソッドによって返されるリソースが正しく破棄されるかをチェックできるようになりました。

[MustDisposeResource]
private static Task<Hoge> Task()
{
    return default;
}

public static async void Execute()
{
    // ローカル変数 'x' は破棄されません
    var x = await Task();
}

pleiades.io

UniTaskに対応しているかどうか

UniTaskには対応してないのではという話が上がっていたのですが、普通に対応してました。

[MustDisposeResource]
private static async UniTask<Hoge> UniTask()
{
    return new Hoge(default);
}

public static async void Execute()
{
    // ローカル変数 'y' は破棄されません
    var y = await UniTask();
    _ = y;
}

おそらく以下の文言で言うところのtask-likeに該当しそうです。

タスクのような戻り値: 2024.1 バージョンでのタスクのような戻り値の正しい分析により、待機中のリソースが破棄されるかどうかがチェックされ、.ConfigureAwait(...)、.AsTask()、または .Result を介して取得されたリソースも含まれます。

pleiades.io

実験

Rider2026.1.4で以下のコードを試したところ、適切に警告が表示されていました。

public class Test
{
    [MustDisposeResource]
    private static async Task<Hoge> Task()
    {
        return new Hoge();
    }
    
    [MustDisposeResource]
    private static async UniTask<Hoge> UniTask()
    {
        return new Hoge();
    }

    public static async void Execute()
    {
        // ローカル変数 'x' は破棄されません
        var x = await Task();
        _ = x;
        
        // ローカル変数 'y' は破棄されません
        var y = await UniTask();
        _ = y;
    }
}