如何使用 StreamReader.ReadAsync(Memory<Char>, CancellationToken)

Mic*_*ael 6 c# .net-core

我正在尝试使用StreamReader.ReadAsync(Memory, CancellationToken) 重载,它接受Memory<T>. 这是示例代码:(.NET Core 2.1)

static async Task Main(string[] args)
{
    string code = "Hello, World";
    var memoryStream = Encoding.UTF8.GetBytes(code.ToCharArray(), 0, code.Length);
    using (var stream = new MemoryStream(memoryStream))
    using (var reader = new StreamReader(stream))
    {
        // var text = await reader.ReadLineAsync();
        // Console.WriteLine(text); -> Outputs: Hello, World

        Memory<char> memory = new Memory<char>();
        await reader.ReadAsync(memory);

        Console.WriteLine("Memory<char> length:" + memory.Length);
    }

}
Run Code Online (Sandbox Code Playgroud)

代码尝试读取字符串内容StreamReader并填充Memory<char>。但是,代码的Memory<char>长度一直输出 0 。

使用此方法填充的正确方法是Memory<char>什么?

我的.csproj文件内容:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <LangVersion>7.2</LangVersion>
  </PropertyGroup>
</Project>
Run Code Online (Sandbox Code Playgroud)

Alo*_*aus 5

有效的解决方案是使用缓冲区初始化内存并关心 ReadAsync 的返回值,以便您知道您读取了多少个字符(不是字节)。

您确实遇到了一个问题,即 Memory 是一个结构体,它总是允许您创建一个没有参数的实例,尽管从 API 使用的角度来看这是不允许的。

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

namespace ReadMemory
{
    class Program
    {
        public static async Task Main(string[] args)
        {
            string code = "Hello, World";
            var memoryStream = Encoding.UTF8.GetBytes(code.ToCharArray(), 0, code.Length);
            using (var stream = new MemoryStream(memoryStream))
            using (var reader = new StreamReader(stream))
            {

                Memory<char> memory = new Memory<char>(new char[1024]);  // Init with backing buffer. Otherwise you are trying to read 0 bytes into a zero sized buffer. 
                int charsRead = await reader.ReadAsync(memory);

                Console.WriteLine($"Memory<char> len: {memory.Length}, bytes read: {charsRead}");
            }

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

回答你第二个问题。是的,您可以使用 ReadAsync(char[] ...) 而不是内存。它们是等效的,因为在引擎盖下它无论如何都作为 System.Memory 进一步传递,然后当涉及到转换为 Span 的实际读数时。看

public virtual System.Threading.Tasks.Task<int> ReadAsync(char[] buffer, int index, int count)
{
    return this.ReadAsyncInternal(new Memory<char>(buffer, index, count), default(System.Threading.CancellationToken)).AsTask();
}
Run Code Online (Sandbox Code Playgroud)