Partilhar via


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

Propriedade 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 causa interrupção ou não Ininterrupto
Habilitado por padrão no .NET 10 Como sugestão
Línguas aplicáveis C# e Visual Basic

Motivo

Esta regra localiza invocações aguardadas das sobrecargas de método baseadas em matriz de bytes para ReadAsync e WriteAsync, e 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 argumentos inteiros offset e count para as instâncias criadas Memory ou 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ções de ReadAsync, sem e com um 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ções de WriteAsync, com e sem um argumento CancellationToken:

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

Inexistência de 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