Udostępnij za pośrednictwem


CA1844: Podaj zastąpienia oparte na pamięci metod asynchronicznych podczas podklasowania "Stream"

Właściwości Wartość
Identyfikator reguły CA1844
Tytuł Udostępnianie przesłonięć opartych na pamięci metod asynchronicznych podczas podklasowania "Stream"
Kategoria Wydajność
Poprawka łamiąca lub nienaruszająca Niezgodność
Domyślnie włączone na platformie .NET 10 Jako sugestia
Zastosowane języki C# i Visual Basic

Przyczyna

Typ pochodzący z Stream przesłania ReadAsync(Byte[], Int32, Int32, CancellationToken), ale nie zastępuje ReadAsync(Memory<Byte>, CancellationToken). Albo typ pochodzący z Stream przesłania WriteAsync(Byte[], Int32, Int32, CancellationToken), ale nie zastępuje WriteAsync(ReadOnlyMemory<Byte>, CancellationToken).

Opis reguły

Oparte na pamięci metody ReadAsync i WriteAsync zostały dodane w celu zwiększenia wydajności, co osiągają na wiele sposobów.

  • Zwracają ValueTask i ValueTask<int> zamiast Task i Task<int>, odpowiednio.
  • Umożliwiają one przekazywanie dowolnego typu bufora bez potrzeby wykonywania dodatkowej kopii do tablicy.

Aby osiągnąć korzyści związane z wydajnością, typy pochodzące z Stream muszą dostarczyć własną implementację opartą na pamięci. W przeciwnym razie domyślna implementacja zostanie zmuszona do skopiowania pamięci do tablicy w celu wywołania implementacji opartej na tablicy, co spowoduje zmniejszenie wydajności. Gdy obiekt wywołujący przekazuje instancję Memory<T> lub ReadOnlyMemory<T>, która nie jest obsługiwana przez tablicę, wydajność jest bardziej obciążona.

Jak naprawić naruszenia

Najprostszym sposobem naprawienia naruszeń jest przepisanie implementacji opartej na tablicy jako implementacji opartej na pamięci, a następnie zaimplementowanie metod opartych na tablicy pod względem metod opartych na pamięci.

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

Kiedy pomijać ostrzeżenia

Można bezpiecznie pominąć ostrzeżenie z tej reguły, jeśli ma zastosowanie którakolwiek z następujących sytuacji:

  • Osiągnięcie wydajności nie jest problemem.
  • Wiesz, że podklasa Stream zawsze będzie używać tylko metod opartych na tablicy.
  • Podklasa Stream ma zależności, które nie obsługują buforów opartych na pamięci.

Pomijanie ostrzeżenia

Jeśli chcesz po prostu pominąć pojedyncze naruszenie, dodaj dyrektywy preprocesora do pliku źródłowego, aby wyłączyć, a następnie ponownie włączyć regułę.

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

Aby wyłączyć regułę dla pliku, folderu lub projektu, ustaw jego ważność na none w pliku konfiguracji.

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

Aby uzyskać więcej informacji, zobacz Jak pominąć ostrzeżenia dotyczące analizy kodu.

Zobacz też