共用方式為


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

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

原因

此規則會找出 和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為您執行,方法是將滑鼠停留在方法調用旁邊顯示的燈泡上,然後選取建議的變更。 範例:

CA1835 的程式代碼修正 - 偏好在串流型類別中使用 ReadAsync/WriteAsync 方法的記憶體型多載

此規則可以偵測和 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

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

另請參閱