Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
| 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 powodująca niezgodność lub niezgodność | Niezgodność |
| Domyślnie włączone na platformie .NET 10 | Jako sugestia |
Przyczyna
Typ pochodzący z Stream przesłonięć ReadAsync(Byte[], Int32, Int32, CancellationToken) , ale nie zastępuje ReadAsync(Memory<Byte>, CancellationToken)elementu . Lub typ pochodzący z Stream przesłonięć WriteAsync(Byte[], Int32, Int32, CancellationToken) , ale nie zastępuje WriteAsync(ReadOnlyMemory<Byte>, CancellationToken).
Opis reguły
Metody i oparte na ReadAsyncWriteAsync pamięci zostały dodane w celu zwiększenia wydajności, co można osiągnąć na wiele sposobów:
- Zwracają
ValueTaskodpowiednio wartości iValueTask<int>zamiastTaskiTask<int>. - Umożliwiają one przekazywanie dowolnego typu buforu bez konieczności wykonywania dodatkowej kopii do tablicy.
Aby zrealizować te korzyści z wydajności, typy pochodzące z Stream programu muszą zapewnić 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 przechodzi w wystąpieniu Memory<T> lub ReadOnlyMemory<T> , które nie jest obsługiwane przez tablicę, wydajność będzie miała większy wpływ.
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
Streambędzie używać tylko metod opartych na tablicy. - Podklasa
Streamma zależności, które nie obsługują 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.