CA1835: Preferuj przeciążenia oparte na pamięci metod ReadAsync/WriteAsync w klasach opartych na strumieniu

Właściwości Wartość
Nazwa typu PreferStreamAsyncMemoryOverloads
Identyfikator reguły CA1835
Tytuł Preferuj przeciążenia oparte na pamięci metod ReadAsync/WriteAsync w klasach opartych na strumieniu
Kategoria Wydajność
Poprawka powodująca niezgodność lub niezgodność Niezgodność
Domyślnie włączone na platformie .NET 8 Jako sugestia

Przyczyna

Ta reguła lokalizuje oczekiwane wywołania przeciążeń metody opartej na tablicy bajtów dla ReadAsync metod i WriteAsynci i sugeruje użycie przeciążeń metody opartej na pamięci, ponieważ są one bardziej wydajne.

Opis reguły

Przeciążenia metody opartej na pamięci mają bardziej wydajne użycie pamięci niż te oparte na tablicy bajtów.

Reguła działa na ReadAsync wywołaniach dowolnej klasy dziedziczonej z Streamklasy i WriteAsync .

Reguła działa tylko wtedy, gdy metoda jest poprzedzona await słowem kluczowym.

Wykryta metoda Sugerowana metoda
ReadAsync(Byte[], Int32, Int32, CancellationToken) ReadAsync(Memory<Byte>, CancellationToken)
ReadAsync(Byte[], Int32, Int32) ReadAsync(Memory<Byte>, CancellationToken) z ustawioną wartością CancellationTokendefault w języku C#lub Nothing w Visual Basic.
WriteAsync(Byte[], Int32, Int32, CancellationToken) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)
WriteAsync(Byte[], Int32, Int32) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) z ustawioną wartością CancellationTokendefault w języku C#lub Nothing w Visual Basic.

Ważne

Pamiętaj, aby przekazać offset argumenty i count liczby całkowite do utworzonych Memory wystąpień lub ReadOnlyMemory .

Uwaga

Reguła CA1835 jest dostępna we wszystkich wersjach platformy .NET, w których dostępne są przeciążenia oparte na pamięci:

  • .NET Standard 2.1 lub nowszy.
  • .NET Core 2.1 lub nowszy.

Jak naprawić naruszenia

Możesz je naprawić ręcznie lub możesz zezwolić programowi Visual Studio na to zrobić, umieszczając wskaźnik myszy na żarówki, która jest wyświetlana obok wywołania metody i wybierając sugerowaną zmianę. Przykład:

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

Reguła może wykrywać różne naruszenia metod ReadAsync i WriteAsync . Oto przykłady przypadków, w których reguła może wykryć:

Przykład 1

Wywołania elementu , bez argumentu ReadAsynci z argumentem 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);
        }
    }
}

Naprawa:

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

Przykład 2

Wywołania elementu , bez argumentu WriteAsynci z argumentem 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);
        }
    }
}

Naprawa:

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

Przykład 3

Wywołania za pomocą polecenia 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);
        }
    }
}

Naprawa:

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

Naruszenia niezwiązane z naruszeniem

Poniżej przedstawiono kilka przykładów wywołań, w których reguła nie zostanie wyzwolona.

Wartość zwracana jest zapisywana w zmiennej Task , a nie oczekiwana:

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

Zwracana jest wartość zwracana przez metodę opakowującego, a nie oczekiwaną:

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

Wartość zwracana jest używana do wywołania ContinueWithmetody , która jest oczekiwana:

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

Kiedy pomijać ostrzeżenia

Można bezpiecznie pominąć naruszenie tej reguły, jeśli nie martwisz się o poprawę wydajności podczas odczytywania lub zapisywania buforów w klasach opartych na strumieniu.

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 CA1835
// The code that's violating the rule is on this line.
#pragma warning restore CA1835

Aby wyłączyć regułę dla pliku, folderu lub projektu, ustaw jego ważność na none w pliku konfiguracji.

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

Aby uzyskać więcej informacji, zobacz Jak pominąć ostrzeżenia dotyczące analizy kodu.

Zobacz też