CA1844: 'Stream' sınıfının alt sınıfı oluşturulurken zaman uyumsuz yöntemlerin bellek tabanlı geçersiz kılmalarını sağlayın

Özellik Değer
Kural Kimliği CA1844
Başlık 'Stream' alt sınıfını oluştururken zaman uyumsuz yöntemlerin bellek üzerinde geçersiz kılmalarını sağlayın
Kategori Performans
Düzeltme bozucu ya da bozmayan olabilir Kesintisiz
.NET 10'da varsayılan olarak etkin Öneri olarak
Geçerli diller C# ve Visual Basic

Neden

Stream türetilen bir tür, ReadAsync(Byte[], Int32, Int32, CancellationToken) geçersiz kılar ancak ReadAsync(Memory<Byte>, CancellationToken) geçersiz kılmaz. Veya, Stream türetilmiş ancak WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) geçersiz kılmayan bir WriteAsync(Byte[], Int32, Int32, CancellationToken) türü.

Kural açıklaması

Bellek tabanlı ReadAsync ve WriteAsync yöntemler, performansı geliştirmek için eklenmiştir ve bunu birden çok yolla gerçekleştirirler:

  • ValueTask ve ValueTask<int>, sırasıyla Task ve Task<int> yerine döndürürler.
  • Ek bir kopya gerçekleştirmek zorunda kalmadan herhangi bir arabellek türünün diziye geçirilmesine izin verir.

Bu performans avantajlarını gerçekleştirmek için, Stream'den türetilen türlerin bellek tabanlı kendi uygulamalarını sağlaması gerekir. Aksi takdirde, varsayılan uygulama dizi tabanlı uygulamayı çağırmak için belleği bir diziye kopyalamaya zorlanır ve bu da performansın düşmesine neden olur. Çağıran, bir dizi tarafından desteklenmeyen bir Memory<T> veya ReadOnlyMemory<T> örneğini geçtiğinde performans daha fazla etkilenir.

İhlalleri düzeltme

İhlalleri düzeltmenin en kolay yolu, dizi tabanlı uygulamanızı bellek tabanlı bir uygulama olarak yeniden yazmak ve ardından dizi tabanlı yöntemleri bellek tabanlı yöntemler açısından uygulamaktır.

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

Uyarıların ne zaman bastırılması gerekiyor?

Aşağıdaki durumlardan herhangi biri geçerliyse, bu kuraldan gelen bir uyarıyı engellemek güvenlidir:

  • Performans isabeti önemli değildir.
  • Alt sınıfınızın Stream yalnızca dizi tabanlı yöntemleri kullanacağını biliyorsunuz.
  • Stream alt sınıfınızda, bellek tabanlı arabellekleri desteklemeyen bağımlılıklar var.

Uyarıyı gizleme

Yalnızca tek bir ihlali engellemek istiyorsanız, kuralı devre dışı bırakmak ve sonra yeniden etkinleştirmek için kaynak dosyanıza ön işlemci yönergeleri ekleyin.

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

Bir dosya, klasör veya projenin kuralını devre dışı bırakmak için, yapılandırma dosyasındaki önem derecesini noneolarak ayarlayın.

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

Daha fazla bilgi için bkz . Kod analizi uyarılarını gizleme.

Ayrıca bkz.