CA1835:偏好在資料流程型類別中以記憶體為基礎的 ReadAsync/WriteAsync 方法多載

屬性
類型名稱 PreferStreamAsyncMemoryOverloads
規則識別碼 CA1835
標題 偏好以記憶體為基礎的多載在資料流程型類別中 ReadAsync/WriteAsync 方法
類別 效能
修正程式是中斷或非中斷 不中斷
預設在 .NET 8 中啟用 建議

原因

此規則會找出 和 WriteAsync 的位元組陣列型方法多載 ReadAsync 的等候調用,並建議改用以記憶體為基礎的方法多載,因為它們更有效率。

檔案描述

記憶體型方法多載的記憶體使用量比位元組陣列型多載更有效率。

規則適用于 ReadAsync 繼承自 Stream 的任何類別和 WriteAsync 叫用。

只有在 方法前面加上 await 關鍵字時,規則才有效。

偵測到的方法 建議的方法
ReadAsync(Byte[], Int32, Int32, CancellationToken) ReadAsync(Memory<Byte>, CancellationToken)
ReadAsync(Byte[], Int32, Int32) ReadAsync(Memory<Byte>, CancellationToken)CancellationToken C# 或 Nothing Visual Basic 中設定為 default
WriteAsync(Byte[], Int32, Int32, CancellationToken) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)
WriteAsync(Byte[], Int32, Int32) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)CancellationToken C# 或 Nothing Visual Basic 中設定為 default

重要

請務必將 offsetcount 整數引數傳遞至已建立 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

此規則可以偵測 和 WriteAsync 方法的各種違規 ReadAsync 。 以下是規則可以偵測到的案例範例:

範例 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);
        }
    }
}

傳回值是由 wrapping 方法傳回,而不是等候:

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

如需詳細資訊,請參閱 如何隱藏程式碼分析警告

另請參閱