Share via


CA1835: 스트림 기반 클래스에서 ReadAsync/WriteAsync 메서드의 메모리 기반 오버로드 선호

속성
형식 이름 PreferStreamAsyncMemoryOverloads
규칙 ID CA1835
타이틀 스트림 기반 클래스에서 ReadAsync/WriteAsync 메서드의 메모리 기반 오버로드를 선호합니다.
범주 성능
수정 사항이 주요 변경인지 여부 주요 변경 아님
.NET 8에서 기본적으로 사용 제안 사항

원인

이 규칙은 ReadAsyncWriteAsync에 대한 바이트 배열 기반 메서드 오버로드의 대기된 호출을 찾고 보다 효율적인 메모리 기반 메서드 오버로드를 대신 사용하도록 제안합니다.

규칙 설명

메모리 기반 메서드 오버로드는 바이트 배열 기반 메서드 오버로드에 비해 메모리 사용이 더 효율적입니다.

규칙은 Stream에서 상속되는 클래스의 ReadAsyncWriteAsync 호출에서 작동합니다.

규칙은 메서드가 await 키워드 뒤에 오는 경우에만 작동합니다.

검색된 메서드 제안된 메서드
ReadAsync(Byte[], Int32, Int32, CancellationToken) ReadAsync(Memory<Byte>, CancellationToken)
ReadAsync(Byte[], Int32, Int32) CancellationTokendefault(C#) 또는 Nothing(Visual Basic)으로 설정된 ReadAsync(Memory<Byte>, CancellationToken)
WriteAsync(Byte[], Int32, Int32, CancellationToken) WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)
WriteAsync(Byte[], Int32, Int32) CancellationTokendefault(C#) 또는 Nothing(Visual Basic)으로 설정된 WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)

Important

생성된 Memory 또는 ReadOnlyMemory 인스턴스에 offsetcount 정수 인수를 전달해야 합니다.

참고 항목

규칙 CA1835는 메모리 기반 오버로드를 사용할 수 있는 모든 .NET 버전에서 사용할 수 있습니다.

  • .NET Standard 2.1 이상
  • .NET Core 2.1 이상

위반 문제를 해결하는 방법

수동으로 수정하거나, 메서드 호출 옆에 표시되는 전구를 마우스로 가리키고 제안된 변경 내용을 선택하여 Visual Studio에서 자동으로 수정하도록 선택할 수 있습니다. 예시:

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

규칙은 ReadAsyncWriteAsync 메서드에 대한 다양한 위반을 탐지할 수 있습니다. 다음은 규칙이 탐지할 수 있는 사례에 대한 예입니다.

예 1

CancellationToken 인수를 사용하거나 사용하지 않는 ReadAsync의 호출:

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

Fix:

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

예제 2

CancellationToken 인수를 사용하거나 사용하지 않는 WriteAsync의 호출:

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

Fix:

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

예 3

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

Fix:

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

위반 없음

다음은 규칙이 발생하지 ‘않을’ 호출의 몇 가지 예입니다.

반환 값이 대기하는 대신 Task 변수에 저장됩니다.

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

반환 값이 대기하는 대신 래핑 메서드에서 반환됩니다.

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

반환 값이 대기 중인 메서드인 ContinueWith를 호출하는 데 사용됩니다.

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

경고를 표시하지 않는 경우

스트림 기반 클래스에서 버퍼를 읽거나 쓸 때 성능 향상을 우려하지 않는 경우 이 규칙의 위반을 표시하지 않는 것이 안전합니다.

경고 표시 안 함

단일 위반만 표시하지 않으려면 원본 파일에 전처리기 지시문을 추가하여 규칙을 사용하지 않도록 설정한 후 다시 사용하도록 설정합니다.

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

파일, 폴더 또는 프로젝트에 대한 규칙을 사용하지 않도록 설정하려면 구성 파일에서 심각도를 none으로 설정합니다.

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

자세한 내용은 방법: 코드 분석 경고 표시 안 함을 참조하세요.

참고 항목