CA1835 : Préférer les surcharges basées sur la mémoire des méthodes ReadAsync/WriteAsync dans les classes basées sur un flux

Propriété Valeur
Nom du type PreferStreamAsyncMemoryOverloads
Identificateur de la règle CA1835
Titre Préférer les surcharges basées sur la mémoire des méthodes ReadAsync/WriteAsync dans les classes basées sur un flux
Catégorie Performances
Le correctif est cassant ou non cassant Sans rupture
Activé par défaut dans .NET 8 À titre de suggestion

Cause

Cette règle localise les appels attendus des surcharges de méthode basées sur un tableau d’octets pour ReadAsync et WriteAsync, et suggère d’utiliser les surcharges de méthode basées sur la mémoire à la place, car elles sont plus efficaces.

Description de la règle

Les surcharges de méthode basées sur la mémoire ont une utilisation de la mémoire plus efficace que celles basées sur un tableau d’octets.

La règle fonctionne sur les appels ReadAsync et WriteAsync de toute classe qui hérite de Stream.

La règle fonctionne uniquement quand la méthode est précédée du mot clé await.

Méthode détectée Méthode suggérée
ReadAsync(Byte[], Int32, Int32, CancellationToken) ReadAsync(Memory<Byte>, CancellationToken)
ReadAsync(Byte[], Int32, Int32) ReadAsync(Memory<Byte>, CancellationToken) avec CancellationToken défini sur default en C#, ou Nothing en Visual Basic.
WriteAsync(Byte[], Int32, Int32, CancellationToken) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)
WriteAsync(Byte[], Int32, Int32) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) avec CancellationToken défini sur default en C#, ou Nothing en Visual Basic.

Important

Veillez à passer les arguments entiers offset et count aux instances Memory ou ReadOnlyMemory créées.

Notes

La règle CA1835 est disponible dans toutes les versions de .NET où les surcharges basées sur la mémoire sont disponibles :

  • .NET Standard 2.1 et versions ultérieures.
  • .NET Core 2.1 et versions ultérieures.

Comment corriger les violations

Vous pouvez les corriger manuellement ou choisir de laisser Visual Studio le faire pour vous. Il vous suffit de pointer sur l’ampoule qui s’affiche à côté de l’appel de méthode et de sélectionner le changement suggéré. Exemple :

Code fix for CA1835 - Prefer the memory-based overloads of ReadAsync/WriteAsync methods in stream-based classes

La règle peut détecter diverses violations pour les méthodes ReadAsync et WriteAsync. Voici des exemples de cas que la règle peut détecter :

Exemple 1

Appels de ReadAsync, avec et sans argument CancellationToken :

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod(CancellationToken ct)
    {
        using (FileStream s = new FileStream("path.txt", FileMode.Create))
        {
            byte[] buffer = new byte[s.Length];
            await s.ReadAsync(buffer, 0, buffer.Length);
            await s.ReadAsync(buffer, 0, buffer.Length, ct);
        }
    }
}

Correctif :

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod(CancellationToken ct)
    {
        using (FileStream s = new FileStream("path.txt", FileMode.Create))
        {
            byte[] buffer = new byte[s.Length];
            await s.ReadAsync(buffer.AsMemory(0, buffer.Length));
            await s.ReadAsync(buffer.AsMemory(0, buffer.Length), ct);
        }
    }
}

Exemple 2

Appels de WriteAsync, avec et sans argument CancellationToken :

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod(CancellationToken ct)
    {
        using (FileStream s = File.Open("path.txt", FileMode.Open))
        {
            byte[] buffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
            await s.WriteAsync(buffer, 0, buffer.Length);
            await s.WriteAsync(buffer, 0, buffer.Length, ct);
        }
    }
}

Correctif :

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod()
    {
        using (FileStream s = File.Open("path.txt", FileMode.Open))
        {
            byte[] buffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
            await s.WriteAsync(buffer.AsMemory(0, buffer.Length));
            await s.WriteAsync(buffer.AsMemory(0, buffer.Length), ct);
        }
    }
}

Exemple 3

Appels avec ConfigureAwait :

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod()
    {
        using (FileStream s = File.Open("path.txt", FileMode.Open))
        {
            byte[] buffer1 = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
            await s.WriteAsync(buffer1, 0, buffer1.Length).ConfigureAwait(false);

            byte[] buffer2 = new byte[s.Length];
            await s.ReadAsync(buffer2, 0, buffer2.Length).ConfigureAwait(true);
        }
    }
}

Correctif :

using System;
using System.IO;
using System.Threading;

class MyClass
{
    public async void MyMethod()
    {
        using (FileStream s = File.Open("path.txt", FileMode.Open))
        {
            byte[] buffer1 = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
            await s.WriteAsync(buffer1.AsMemory(0, buffer1.Length)).ConfigureAwait(false);

            byte[] buffer2 = new byte[s.Length];
            await s.ReadAsync(buffer2.AsMemory(0, buffer.Length)).ConfigureAwait(true);
        }
    }
}

Non-violations

Voici quelques exemples d’appels dans lesquels la règle n’est pas déclenchée.

La valeur de retour est enregistrée dans une variable Task au lieu d’être attendue :

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

class MyClass
{
    public void MyMethod()
    {
        byte[] buffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
        using (FileStream s = new FileStream("path.txt", FileMode.Create))
        {
            Task t = s.WriteAsync(buffer, 0, buffer.Length);
        }
    }
}

La valeur de retour est renvoyée par la méthode de wrapping au lieu d’être attendue :

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

class MyClass
{
    public Task MyMethod(FileStream s, byte[] buffer)
    {
        return s.WriteAsync(buffer, 0, buffer.Length);
    }
}

La valeur de retour est utilisée pour appeler ContinueWith, qui est la méthode attendue :

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

class MyClass
{
    public void MyMethod()
    {
        byte[] buffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
        using (FileStream s = new FileStream("path.txt", FileMode.Create))
        {
            await s.WriteAsync(buffer, 0, buffer.Length).ContinueWith(c => { /* ... */ });
        }
    }
}

Quand supprimer les avertissements

Vous pouvez supprimer une violation de cette règle si vous n’avez pas besoin d’améliorer les performances pendant la lecture ou l’écriture des tampons dans les classes basées sur un flux.

Supprimer un avertissement

Si vous voulez supprimer une seule violation, ajoutez des directives de préprocesseur à votre fichier source pour désactiver et réactiver la règle.

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

Pour désactiver la règle sur un fichier, un dossier ou un projet, définissez sa gravité sur none dans le fichier de configuration.

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

Pour plus d’informations, consultez Comment supprimer les avertissements de l’analyse de code.

Voir aussi