Бөлісу құралы:


CA1844: обеспечение переопределения асинхронных методов на основе памяти при создании подкласса Stream

Свойство Значение
Идентификатор правила CA1844
Заголовок Предоставьте переопределения на основе памяти асинхронных методов при подклассе Stream.
Категория Производительность
Исправление является критическим или не критическим Не критическое
Включен по умолчанию в .NET 10 Как предложение

Причина

Тип, производный от 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

Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.

См. также