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 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 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:
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.