Partilhar via


CA1835: Prefira as sobrecargas baseadas em memória dos métodos ReadAsync/WriteAsync em classes baseadas em fluxo

Property valor
Nome do tipo PreferStreamAsyncMemoryOverloads
ID da regra CA1835
Título Prefira as sobrecargas baseadas em memória dos métodos ReadAsync/WriteAsync em classes baseadas em fluxo
Categoria Desempenho
A correção está quebrando ou não quebrando Sem quebra
Habilitado por padrão no .NET 9 Como sugestão

Motivo

Esta regra localiza invocações aguardadas das sobrecargas de método baseadas em matriz de bytes para ReadAsync e WriteAsynce sugere o uso das sobrecargas de método baseadas em memória, porque elas são mais eficientes.

Descrição da regra

As sobrecargas de método baseadas em memória têm um uso de memória mais eficiente do que as sobrecargas baseadas em matriz de bytes.

A regra funciona em ReadAsync e WriteAsync invocações de qualquer classe que herda de Stream.

A regra só funciona quando o método é precedido await pela palavra-chave.

Método detetado Método sugerido
ReadAsync(Byte[], Int32, Int32, CancellationToken) ReadAsync(Memory<Byte>, CancellationToken)
ReadAsync(Byte[], Int32, Int32) ReadAsync(Memory<Byte>, CancellationToken) com CancellationToken definido como default em C# ou Nothing em Visual Basic.
WriteAsync(Byte[], Int32, Int32, CancellationToken) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)
WriteAsync(Byte[], Int32, Int32) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) com CancellationToken definido como default em C# ou Nothing em Visual Basic.

Importante

Certifique-se de passar os offset argumentos e count inteiros para as instâncias ou criadas Memory ReadOnlyMemory .

Nota

A regra CA1835 está disponível em todas as versões do .NET em que as sobrecargas baseadas em memória estão disponíveis:

  • .NET Standard 2.1 e superior.
  • .NET Core 2.1 e superior.

Como corrigir violações

Você pode corrigi-los manualmente ou pode optar por deixar o Visual Studio fazer isso por você, passando o mouse sobre a lâmpada que aparece ao lado da chamada do método e selecionando a alteração sugerida. Exemplo:

Correção de código para CA1835 - Prefira as sobrecargas baseadas em memória dos métodos ReadAsync/WriteAsync em classes baseadas em fluxo

A regra pode detetar uma variedade de violações para o ReadAsync e WriteAsync métodos. Aqui estão exemplos dos casos que a regra pode detetar:

Exemplo 1

Invocação de ReadAsync, sem e com CancellationToken argumento:

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

Correção:

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

Exemplo 2

Invocação de WriteAsync, sem e com CancellationToken argumento:

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

Correção:

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

Exemplo 3

Invocações com 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);
        }
    }
}

Correção:

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

Não violações

Seguem-se alguns exemplos de invocações em que a regra não será acionada.

O valor de retorno é salvo em uma Task variável em vez de ser aguardado:

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

O valor de retorno é retornado pelo método de encapsulamento em vez de ser aguardado:

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

O valor de retorno é usado para chamar ContinueWith, que é o método que está sendo aguardado:

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 => { /* ... */ });
        }
    }
}

Quando suprimir avisos

É seguro suprimir uma violação dessa regra se você não estiver preocupado em melhorar o desempenho ao ler ou gravar buffers em classes baseadas em fluxo.

Suprimir um aviso

Se você quiser apenas suprimir uma única violação, adicione diretivas de pré-processador ao seu arquivo de origem para desativar e, em seguida, reativar a regra.

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

Para desabilitar a regra de um arquivo, pasta ou projeto, defina sua gravidade como none no arquivo de configuração.

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

Para obter mais informações, consulte Como suprimir avisos de análise de código.

Consulte também