Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
| Propiedad | Value |
|---|---|
| Identificador de la regla | CA1844 |
| Título | Proporcionar invalidaciones basadas en memoria de métodos asincrónicos al crear subclases de 'Stream' |
| Categoría | Rendimiento |
| La corrección es problemática o no problemática | Poco problemático |
| Habilitado de forma predeterminada en .NET 10 | Como sugerencia |
Causa
Un tipo derivado de Stream invalida ReadAsync(Byte[], Int32, Int32, CancellationToken), pero no ReadAsync(Memory<Byte>, CancellationToken). O bien, un tipo derivado de Stream invalida a WriteAsync(Byte[], Int32, Int32, CancellationToken), pero no a WriteAsync(ReadOnlyMemory<Byte>, CancellationToken).
Descripción de la regla
Los métodos ReadAsync y WriteAsync basados en memoria se agregaron para mejorar el rendimiento, lo que logran de varias maneras:
- Devuelven
ValueTaskyValueTask<int>en lugar deTaskyTask<int>, respectivamente. - Permiten pasar cualquier tipo de búfer sin tener que realizar una copia adicional en una matriz.
Para lograr estas ventajas de rendimiento, los tipos que derivan de Stream deben proporcionar su propia implementación basada en memoria. De lo contrario, la implementación predeterminada se verá obligada a copiar la memoria en una matriz para llamar a la implementación basada en matriz, lo que reduce el rendimiento. Cuando el autor de la llamada pasa una instancia de Memory<T> o ReadOnlyMemory<T> que no está copiada en una matriz, el rendimiento se ve más afectado.
Cómo corregir infracciones
La manera más fácil de corregir infracciones es volver a escribir la implementación basada en matriz como una implementación basada en memoria y luego implementar los métodos basados en matrices conforme a los métodos basados en memoria.
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);
}
Cuándo suprimir las advertencias
Es seguro suprimir una advertencia de esta regla si se aplica alguna de las siguientes situaciones:
- El impacto sobre el rendimiento no es un problema.
- Se sabe que la subclase
Streamsolo va a usar los métodos basados en matriz. - La subclase
Streamtiene dependencias que no admiten búferes basados en memoria.
Supresión de una advertencia
Si solo quiere suprimir una única infracción, agregue directivas de preprocesador al archivo de origen para deshabilitar y volver a habilitar la regla.
#pragma warning disable CA1844
// The code that's violating the rule is on this line.
#pragma warning restore CA1844
Para deshabilitar la regla de un archivo, una carpeta o un proyecto, establezca su gravedad en none del archivo de configuración.
[*.{cs,vb}]
dotnet_diagnostic.CA1844.severity = none
Para obtener más información, consulte Procedimiento para suprimir advertencias de análisis de código.