CA1835: предпочитать перегрузки методов ReadAsync/WriteAsync, основанные на памяти, в классах, основанных на потоках
Свойство | Значение |
---|---|
Имя типа | PreferStreamAsyncMemoryOverloads |
Идентификатор правила | CA1835 |
Заголовок | Предпочитайте перегрузки на основе памяти методов ReadAsync/WriteAsync в классах на основе потоков |
Категория | Производительность |
Исправление является критическим или не критическим | Не критическое |
Включен по умолчанию в .NET 8 | Как предложение |
Причина
Это правило находит ожидающие вызовы перегрузок методов на основе массивов байтов для ReadAsync
и WriteAsync
и предлагает использовать перегрузки методов на основе памяти, так как они более эффективны.
Описание правила
Перегрузки методов на основе памяти используют память более эффективно по сравнению с перегрузками методов на основе массивов байтов.
Правило работает с вызовами ReadAsync
и WriteAsync
любого класса, наследуемого от Stream.
Правило работает только в том случае, если перед методом стоит ключевое слово await
.
Обнаруженный метод | Предлагаемый метод |
---|---|
ReadAsync(Byte[], Int32, Int32, CancellationToken) | ReadAsync(Memory<Byte>, CancellationToken) |
ReadAsync(Byte[], Int32, Int32) | ReadAsync(Memory<Byte>, CancellationToken) с параметром CancellationToken , имеющим значение default в C# или Nothing в Visual Basic. |
WriteAsync(Byte[], Int32, Int32, CancellationToken) | WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) |
WriteAsync(Byte[], Int32, Int32) | WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) с параметром CancellationToken , имеющим значение default в C# или Nothing в Visual Basic. |
Важно!
Не забудьте передать целочисленные аргументы offset
и count
в созданные экземпляры Memory
или ReadOnlyMemory
.
Примечание.
Правило CA1835 доступно во всех версиях .NET, в которых имеются перегрузки на основе памяти:
- .NET Standard 2.1 и более поздние версии.
- .NET Core 2.1 и более поздние версии.
Устранение нарушений
Вы можете устранить их вручную или позволить Visual Studio сделать это автоматически, наведя указатель мыши на лампочку рядом с вызовом метода и выбрав предлагаемое изменение. Пример:
Правило может обнаруживать различные нарушения для методов ReadAsync
и WriteAsync
. Ниже приведены примеры случаев, которые может обнаружить это правило:
Пример 1
Вызовы ReadAsync
с аргументом 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);
}
}
}
Исправление:
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
Вызовы WriteAsync
с аргументом 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);
}
}
}
Исправление:
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);
}
}
}
Возвращаемое значение не ожидается, а возвращается методом переноса:
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
Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.