CA1835: Bevorzugen von arbeitsspeicherbasierten Überladungen von ReadAsync-/WriteAsync-Methoden in streambasierten Klassen

Eigenschaft Wert
Typname PreferStreamAsyncMemoryOverloads
Regel-ID CA1835
Titel Bevorzugen von arbeitsspeicherbasierten Überladungen von ReadAsync-/WriteAsync-Methoden in streambasierten Klassen
Kategorie Leistung
Fix führt oder führt nicht zur Unterbrechung Nicht unterbrechend
Standardmäßig in .NET 9 aktiviert Als Vorschlag

Ursache

Diese Regel sucht nach erwarteten Aufrufen der Bytearray-basierten Methodenüberladungen für ReadAsync und WriteAsync und schlägt vor, stattdessen die arbeitsspeicherbasierten Methodenüberladungen zu verwenden, da diese effizienter sind.

Regelbeschreibung

Die arbeitsspeicherbasierten Methodenüberladungen weisen eine effizientere Arbeitsspeicherauslastung als die Bytearray-basierten Überlastungen auf.

Die Regel funktioniert für ReadAsync- und WriteAsync-Aufrufe einer beliebigen Klasse, die von Stream erbt.

Die Regel funktioniert nur, wenn der Methode das Schlüsselwort await vorangestellt ist.

Erkannte Methode Vorgeschlagene Methode
ReadAsync(Byte[], Int32, Int32, CancellationToken) ReadAsync(Memory<Byte>, CancellationToken)
ReadAsync(Byte[], Int32, Int32) ReadAsync(Memory<Byte>, CancellationToken), wobei CancellationToken in C# auf default und in Visual Basic auf Nothing festgelegt ist
WriteAsync(Byte[], Int32, Int32, CancellationToken) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)
WriteAsync(Byte[], Int32, Int32) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken), wobei CancellationToken in C# auf default und in Visual Basic auf Nothing festgelegt ist

Wichtig

Achten Sie darauf, das offset-Argument und das ganzzahlige count-Argument an die erstellte Memory- oder ReadOnlyMemory-Instanz zu übergeben

Hinweis

Die Regel CA1835 ist in allen .NET-Versionen verfügbar, in denen die arbeitsspeicherbasierte Überladungen verfügbar sind:

  • .NET Standard 2.1 und höher
  • .NET Core 2.1 und höher

Behandeln von Verstößen

Sie können Verstöße entweder manuell beheben oder dies Visual Studio überlassen. Sie müssen nur mit dem Mauszeiger auf die Glühbirne neben dem Methodenaufruf zeigen und die vorgeschlagene Änderung auswählen. Beispiel:

Codefix für CA1835: Bevorzugen von arbeitsspeicherbasierten Überladungen von ReadAsync-/WriteAsync-Methoden in streambasierten Klassen

Die Regel kann eine Vielzahl von Verstößen gegen die Methoden ReadAsync und WriteAsync erkennen. Im Folgenden finden Sie einige Beispiele für die Fälle, die die Regel erkennen kann:

Beispiel 1

Aufrufe von ReadAsync, mit und ohne CancellationToken-Argument:

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

Behebung:

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

Beispiel 2

Aufrufe von WriteAsync, mit und ohne CancellationToken-Argument:

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

Behebung:

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

Beispiel 3

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

Behebung:

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

Fälle, die keinen Verstoß darstellen

Im Folgenden finden Sie einige Beispiele für Aufrufe, bei denen die Regel nicht ausgelöst wird.

Der Rückgabewert wird in einer Task-Variablen gespeichert, nicht abgewartet:

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

Der Rückgabewert wird von der umschließenden Methode zurückgegeben, nicht abgewartet:

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

Mit dem Rückgabewert wird ContinueWith aufgerufen, wobei es sich um die erwartete Methode handelt:

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 => { /* ... */ });
        }
    }
}

Wann sollten Warnungen unterdrückt werden?

Verstöße gegen diese Regel können bedenkenlos unterdrückt werden, wenn Sie keine Bedenken hinsichtlich der Verbesserung der Leistung beim Lesen oder Schreiben aus bzw. in Puffer in streambasierten Klassen haben.

Unterdrücken einer Warnung

Um nur eine einzelne Verletzung zu unterdrücken, fügen Sie der Quelldatei Präprozessoranweisungen hinzu, um die Regel zu deaktivieren und dann wieder zu aktivieren.

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

Um die Regel für eine Datei, einen Ordner oder ein Projekt zu deaktivieren, legen Sie den Schweregrad in der Konfigurationsdatei auf none fest.

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

Weitere Informationen finden Sie unter Vorgehensweise: Unterdrücken von Codeanalyse-Warnungen.

Siehe auch