CA1835:在基于流的类中,首选 ReadAsync/WriteAsync 方法的基于内存的重载
属性 | 值 |
---|---|
类型名称 | PreferStreamAsyncMemoryOverloads |
规则 ID | CA1835 |
标题 | 在基于流的类中,首选 ReadAsync/WriteAsync 方法的基于内存的重载 |
类别 | “性能” |
修复是中断修复还是非中断修复 | 非中断 |
在 .NET 8 中默认启用 | 作为建议 |
原因
此规则查找 ReadAsync
和 WriteAsync
的基于字节数组的方法重载的等待调用,并建议改为使用基于内存的方法重载,因为它们的效率更高。
规则说明
基于内存的方法重载具有比基于字节数组的重载更有效的内存使用。
此规则适用于从 Stream 继承的任何类的 ReadAsync
和 WriteAsync
调用。
仅当方法前面带有 await
关键字时,此规则才有效。
检测到的方法 | 建议的方法 |
---|---|
ReadAsync(Byte[], Int32, Int32, CancellationToken) | ReadAsync(Memory<Byte>, CancellationToken) |
ReadAsync(Byte[], Int32, Int32) | CancellationToken 设置为 default (在 C# 中)或 Nothing (在 Visual Basic 中)的 ReadAsync(Memory<Byte>, CancellationToken)。 |
WriteAsync(Byte[], Int32, Int32, CancellationToken) | WriteAsync(ReadOnlyMemory<Byte>, CancellationToken) |
WriteAsync(Byte[], Int32, Int32) | CancellationToken 设置为 default (在 C# 中)或 Nothing (在 Visual Basic 中)的 WriteAsync(ReadOnlyMemory<Byte>, CancellationToken)。 |
重要
确保将 offset
和 count
整数参数传递到创建的 Memory
或 ReadOnlyMemory
实例。
注意
规则 CA1835 适用于所有提供基于内存的重载的 .NET 版本:
- .NET Standard 2.1 及更高版本。
- .NET Core 2.1 及更高版本。
如何解决冲突
可以手动修复,也可以选择让 Visual Studio 执行修复,方法是将鼠标悬停在方法调用旁显示的灯泡图标上,然后选择建议的更改。 示例:
此规则可以检测 ReadAsync
和 WriteAsync
方法的多种冲突。 下面是此规则可检测到的情况示例:
示例 1
ReadAsync
的调用,未使用和使用 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);
}
}
}
解决方法:
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
WriteAsync
的调用,未使用和使用 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);
}
}
}
解决方法:
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);
}
}
}
解决方法:
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
有关详细信息,请参阅如何禁止显示代码分析警告。