次の方法で共有


CA1835: ストリームベースのクラスで ReadAsync/WriteAsync メソッドのメモリベースのオーバーロードを優先する

プロパティ
型名 PreferStreamAsyncMemoryOverloads
ルール ID CA1835
Title ストリームベースのクラスで ReadAsync/WriteAsync メソッドのメモリベースのオーバーロードを優先する
[カテゴリ] パフォーマンス
修正が中断ありか中断なしか なし
.NET 8 では既定で有効 提案として

原因

この規則は、ReadAsync および WriteAsync のバイト配列ベースのメソッドのオーバーロードの待機中の呼び出しを特定し、より効率的であるという理由から、代わりにメモリベースのメソッドのオーバーロードを使用することを提案します。

規則の説明

メモリベースのメソッドのオーバーロードは、バイト配列ベースのものよりもメモリ使用の効率性に優れています。

この規則は、Stream から継承するすべてのクラスの ReadAsync および WriteAsync 呼び出しで機能します。

この規則は、メソッドの前に await キーワードが付いている場合にのみ機能します。

検出されたメソッド 提案されたメソッド
ReadAsync(Byte[], Int32, Int32, CancellationToken) ReadAsync(Memory<Byte>, CancellationToken)
ReadAsync(Byte[], Int32, Int32) ReadAsync(Memory<Byte>, CancellationToken)CancellationToken は、C# では default に、Visual Basic では Nothing に設定します。
WriteAsync(Byte[], Int32, Int32, CancellationToken) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)
WriteAsync(Byte[], Int32, Int32) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)CancellationToken は、C# では default に、Visual Basic では Nothing に設定します。

重要

offset および count の整数の引数を、作成された Memory または ReadOnlyMemory のインスタンスに渡すようにしてください。

注意

規則 CA1835 は、メモリベースのオーバーロードが使用可能なすべての .NET バージョンで使用できます。

  • .NET Standard 2.1 以降。
  • .NET Core 2.1 以降。

違反の修正方法

これらは手動で修正することも、メソッドの呼び出しの横に表示される電球にマウス カーソルを置いて、提案された変更を選択することによって、Visual Studio に実行を任せることを選ぶこともできます。 例:

Code fix for CA1835 - Prefer the memory-based overloads of ReadAsync/WriteAsync methods in stream-based classes

この規則によって、ReadAsyncWriteAsync メソッドのさまざまな違反を検出できます。 規則が検出できるケースの例を次に示します。

例 1

CancellationToken 引数を指定しないときと指定したときの ReadAsync の呼び出し:

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod(CancellationToken ct)
    {
        using (FileStream s = new FileStream("path.txt", FileMode.Create))
        {
            byte[] buffer = new byte[s.Length];
            await s.ReadAsync(buffer, 0, buffer.Length);
            await s.ReadAsync(buffer, 0, buffer.Length, ct);
        }
    }
}

解決策:

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod(CancellationToken ct)
    {
        using (FileStream s = new FileStream("path.txt", FileMode.Create))
        {
            byte[] buffer = new byte[s.Length];
            await s.ReadAsync(buffer.AsMemory(0, buffer.Length));
            await s.ReadAsync(buffer.AsMemory(0, buffer.Length), ct);
        }
    }
}

例 2

CancellationToken 引数を指定しないときと指定したときの WriteAsync の呼び出し:

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod(CancellationToken ct)
    {
        using (FileStream s = File.Open("path.txt", FileMode.Open))
        {
            byte[] buffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
            await s.WriteAsync(buffer, 0, buffer.Length);
            await s.WriteAsync(buffer, 0, buffer.Length, ct);
        }
    }
}

解決策:

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod()
    {
        using (FileStream s = File.Open("path.txt", FileMode.Open))
        {
            byte[] buffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
            await s.WriteAsync(buffer.AsMemory(0, buffer.Length));
            await s.WriteAsync(buffer.AsMemory(0, buffer.Length), ct);
        }
    }
}

例 3

ConfigureAwait を使用した呼び出し:

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod()
    {
        using (FileStream s = File.Open("path.txt", FileMode.Open))
        {
            byte[] buffer1 = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
            await s.WriteAsync(buffer1, 0, buffer1.Length).ConfigureAwait(false);

            byte[] buffer2 = new byte[s.Length];
            await s.ReadAsync(buffer2, 0, buffer2.Length).ConfigureAwait(true);
        }
    }
}

解決策:

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod()
    {
        using (FileStream s = File.Open("path.txt", FileMode.Open))
        {
            byte[] buffer1 = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
            await s.WriteAsync(buffer1.AsMemory(0, buffer1.Length)).ConfigureAwait(false);

            byte[] buffer2 = new byte[s.Length];
            await s.ReadAsync(buffer2.AsMemory(0, buffer.Length)).ConfigureAwait(true);
        }
    }
}

非違反

次に、規則が実行されない呼び出しの例をいくつか示します。

戻り値は、待機するのではなく、Task 変数に保存されます。

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

class MyClass
{
    public void MyMethod()
    {
        byte[] buffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
        using (FileStream s = new FileStream("path.txt", FileMode.Create))
        {
            Task t = s.WriteAsync(buffer, 0, buffer.Length);
        }
    }
}

戻り値は、待機するのではなく、折り返しメソッドによって返されます。

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

class MyClass
{
    public Task MyMethod(FileStream s, byte[] buffer)
    {
        return s.WriteAsync(buffer, 0, buffer.Length);
    }
}

戻り値は、待機中のメソッド ContinueWith を呼び出すために使用されます。

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

class MyClass
{
    public void MyMethod()
    {
        byte[] buffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
        using (FileStream s = new FileStream("path.txt", FileMode.Create))
        {
            await s.WriteAsync(buffer, 0, buffer.Length).ContinueWith(c => { /* ... */ });
        }
    }
}

どのようなときに警告を抑制するか

ストリームベースのクラスでバッファーの読み取りまたは書き込み時のパフォーマンスの向上に関心がない場合は、この規則の違反を抑制することをお勧めします。

警告を抑制する

単一の違反を抑制するだけの場合は、ソース ファイルにプリプロセッサ ディレクティブを追加して無効にしてから、規則をもう一度有効にします。

#pragma warning disable CA1835
// The code that's violating the rule is on this line.
#pragma warning restore CA1835

ファイル、フォルダー、またはプロジェクトの規則を無効にするには、構成ファイルでその重要度を none に設定します。

[*.{cs,vb}]
dotnet_diagnostic.CA1835.severity = none

詳細については、「コード分析の警告を抑制する方法」を参照してください。

関連項目