Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
| Свойство | Значение |
|---|---|
| Идентификатор правила | CA1844 |
| Заголовок | Предоставьте переопределения на основе памяти асинхронных методов при подклассе Stream. |
| Категория | Производительность |
| Исправление является критическим или не критическим | неразрывный |
| Включен по умолчанию в .NET 10 | Как предложение |
| Применимые языки | C# и Visual Basic |
Причина
Тип, производный от Stream, переопределяет ReadAsync(Byte[], Int32, Int32, CancellationToken), однако не переопределяет ReadAsync(Memory<Byte>, CancellationToken). Или тип, производный от Stream, переопределяет WriteAsync(Byte[], Int32, Int32, CancellationToken), но не переопределяет WriteAsync(ReadOnlyMemory<Byte>, CancellationToken).
Описание правила
Методы ReadAsync и WriteAsync, основанные на памяти, были добавлены для повышения производительности. Они достигают этого несколькими способами:
- возвращают
ValueTaskиValueTask<int>вместоTaskиTask<int>, соответственно; - позволяют передавать любой тип буфера без необходимости выполнения дополнительной копии в массиве.
Чтобы воспользоваться этими преимуществами в плане производительности, типы, производные от Stream, должны предоставлять собственную реализацию, основанную на памяти. В противном случае реализация по умолчанию будет вынуждена скопировать память в массив, чтобы вызвать реализацию на основе массива, что приведет к снижению производительности. Когда вызывающий объект передает экземпляр Memory<T> или ReadOnlyMemory<T>, не поддерживаемый массивом, производительность снижается более существенно.
Устранение нарушений
Самым простым способом устранения нарушений является перезапись реализации на основе массивов в качестве реализации на основе памяти, а затем реализация методов на основе массива в условиях методов на основе памяти.
Example
// This class violates the rule.
public class BadStream : Stream
{
private readonly Stream _innerStream;
public BadStream(Stream innerStream)
{
_innerStream = innerStream;
}
public override bool CanRead => _innerStream.CanRead;
public override bool CanSeek => _innerStream.CanSeek;
public override bool CanWrite => _innerStream.CanWrite;
public override long Length => _innerStream.Length;
public override long Position { get => _innerStream.Position; set => _innerStream.Position = value; }
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
// ...
return await _innerStream.ReadAsync(buffer, offset, count, cancellationToken);
}
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
// ...
await _innerStream.WriteAsync(buffer, offset, count, cancellationToken);
}
// Other required overrides
public override void Flush() => _innerStream.Flush();
public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count);
public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin);
public override void SetLength(long value) => _innerStream.SetLength(value);
public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count);
}
// This class satisfies the rule.
public class GoodStream : Stream
{
private readonly Stream _innerStream;
public GoodStream(Stream innerStream)
{
_innerStream = innerStream;
}
public override bool CanRead => _innerStream.CanRead;
public override bool CanSeek => _innerStream.CanSeek;
public override bool CanWrite => _innerStream.CanWrite;
public override long Length => _innerStream.Length;
public override long Position { get => _innerStream.Position; set => _innerStream.Position = value; }
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
// ...
return await _innerStream.ReadAsync(buffer, cancellationToken);
}
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
// ...
await _innerStream.WriteAsync(buffer, cancellationToken);
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return await this.ReadAsync(buffer.AsMemory(offset, count), cancellationToken);
}
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
await this.WriteAsync(buffer.AsMemory(offset, count), cancellationToken);
}
// Other required overrides
public override void Flush() => _innerStream.Flush();
public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count);
public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin);
public override void SetLength(long value) => _innerStream.SetLength(value);
public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count);
}
Когда лучше отключить предупреждения
Предупреждение по этому правилу можно отключить, если любая из следующих ситуаций применима:
- снижение производительности не является проблемой.
- известно, что подкласс
Streamбудет использовать только методы на основе массивов; - подкласс
Streamимеет зависимости, которые не поддерживают буферы на основе памяти.
Отключение предупреждений
Если вы просто хотите отключить одно нарушение, добавьте директивы препроцессора в исходный файл, чтобы отключить и повторно включить правило.
#pragma warning disable CA1844
// The code that's violating the rule is on this line.
#pragma warning restore CA1844
Чтобы отключить правило для файла, папки или проекта, задайте его серьезность none в файле конфигурации.
[*.{cs,vb}]
dotnet_diagnostic.CA1844.severity = none
Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.