Sdílet prostřednictvím


CA1844: Poskytnutí přepisů asynchronních metod založených na paměti při podtřídě Stream

Vlastnost Hodnota
ID pravidla CA1844
Název Poskytnutí přepisů asynchronních metod založených na paměti při podtřídě Stream
Kategorie Výkon
Oprava způsobující chybu nebo chybu způsobující chybu Nenarušující
Povoleno ve výchozím nastavení v .NET 10 Jako návrh

Příčina

Typ odvozený z Stream přepsání ReadAsync(Byte[], Int32, Int32, CancellationToken) , ale nepřepíše ReadAsync(Memory<Byte>, CancellationToken). Nebo typ odvozený z Stream přepsání WriteAsync(Byte[], Int32, Int32, CancellationToken) , ale nepřepíše WriteAsync(ReadOnlyMemory<Byte>, CancellationToken).

Popis pravidla

Byly přidány metody založené na ReadAsyncWriteAsync paměti, aby se zlepšil výkon, který se dosahuje několika způsoby:

  • ValueTask Vrátí místo ValueTask<int>Task a místo a Task<int>v uvedeném pořadí.
  • Umožňují předání libovolného typu vyrovnávací paměti, aniž by musely provádět další kopii do pole.

Aby bylo možné tyto výhody výkonu realizovat, musí typy odvozené z Stream nich poskytovat vlastní implementaci založenou na paměti. Jinak bude výchozí implementace nucena zkopírovat paměť do pole, aby volala implementaci založenou na poli, což vede ke snížení výkonu. Když volající předá v Memory<T> instanci nebo ReadOnlyMemory<T> instanci, která není maticí, bude mít vliv na výkon více.

Jak opravit porušení

Nejjednodušší způsob, jak opravit porušení, je přepsat implementaci založenou na poli jako implementaci založenou na paměti a pak implementovat metody založené na polích z hlediska metod založených na paměti.

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);
}

Kdy potlačit upozornění

Pokud platí některá z následujících situací, je bezpečné potlačit upozornění z tohoto pravidla:

  • Dosažení výkonu není problém.
  • Víte, že vaše Stream podtřída bude používat pouze metody založené na polích.
  • Vaše Stream podtřída obsahuje závislosti, které nepodporují vyrovnávací paměti.

Potlačení upozornění

Pokud chcete pouze potlačit jedno porušení, přidejte do zdrojového souboru direktivy preprocesoru, abyste pravidlo zakázali a znovu povolili.

#pragma warning disable CA1844
// The code that's violating the rule is on this line.
#pragma warning restore CA1844

Pokud chcete pravidlo pro soubor, složku nebo projekt zakázat, nastavte jeho závažnost v none konfiguračním souboru.

[*.{cs,vb}]
dotnet_diagnostic.CA1844.severity = none

Další informace naleznete v tématu Jak potlačit upozornění analýzy kódu.

Viz také