CA1835: Dar preferência às 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 | Dar preferência às sobrecargas baseadas em memória dos métodos ReadAsync/WriteAsync em classes baseadas em fluxo |
Categoria | Desempenho |
Correção interruptiva ou sem interrupção | Sem interrupção |
Habilitado por padrão no .NET 9 | Como sugestão |
Causa
Essa regra localiza as 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, pois 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 baseadas em matriz de bytes.
A regra funciona nas invocações de ReadAsync
e WriteAsync
de qualquer classe que herde de Stream.
Ela só funciona quando o método é precedido pela palavra-chave await
.
Método detectado | 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
Transmita os argumentos de inteiros offset
e count
para as instâncias criadas de Memory
e ReadOnlyMemory
.
Observação
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-las manualmente ou optar por permitir que o Visual Studio faça isso por você, posicionando o mouse sobre a lâmpada que aparece ao lado da invocação do método e selecionando a alteração sugerida. Exemplo:
A regra pode detectar uma variedade de violações para os métodos ReadAsync
e WriteAsync
. Estes são exemplos dos casos que a regra pode detectar:
Exemplo 1
Invocações de ReadAsync
, sem e com um argumento CancellationToken
:
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
, sem e com 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);
}
}
}
Não violações
Veja a seguir alguns exemplos de invocações em que a regra não será disparada.
O valor retornado é salvo em uma variável Task
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 retornado é 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 retornado é 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 está preocupado em aprimorar o desempenho ao ler ou gravar buffers em classes baseadas em fluxo.
Suprimir um aviso
Para suprimir apenas uma violação, adicione diretivas de pré-processador ao arquivo de origem a fim de desabilitar e, em seguida, reabilitar 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 em um arquivo, uma pasta ou um projeto, defina a severidade como none
no arquivo de configuração.
[*.{cs,vb}]
dotnet_diagnostic.CA1835.severity = none
Para obter mais informações, confira Como suprimir avisos de análise de código.