使用任务在 C# 中进行异步编程

Asynchronous Programming in C# with Tasks

我开始学习异步编程,我偶然发现了这个问题。我通过 Dispatcher.BeginInvoke 调用这些函数。

我希望通过 ReadText 方法获取文件内容,但我得到的只是 "System.Threading.Tasks.Task`1[System.String]"

所以问题是我的代码有什么问题,我应该修复哪一行?

可悲的是,我无法弄清楚我的问题出在哪里,因为我已经查看这段代码已经有一段时间了。

我想因为我得到了对象的时间而不是对象本身,所以我的 ReadText 方法是错误的,但我没有看到在哪里。似乎我在 Stringbuilder 下面的部分或我使这些方法异步的方式有问题。

如果你想知道我为什么使用两种方法,那就是通过 await 和 calling async Task 方法来了解。我还尝试将该方法设为 Tast 方法,但这只会导致更多问题。

提前感谢您的帮助。

    public async void ReadFile()
    {
        string filePath = @"SampleFile.txt";

        if (File.Exists(filePath) == false)
        {
            MessageBox.Show(filePath + " not found", "File Error", MessageBoxButton.OK);
        }
        else
        {
            try
            {
                string text = await ReadText(filePath);                 
                txtContents.Text = text;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }
    }

    private async Task<string> ReadText(string filePath)
    {
        Task Readfile = Task.Run(() =>
        {
            using (FileStream sourceStream = new FileStream(filePath,
                FileMode.Open, FileAccess.Read, FileShare.Read,
                bufferSize: 4096, useAsync: true))
        {
            StringBuilder sb = new StringBuilder();

            byte[] buffer = new byte[0x1000];
            int numRead;
            while ((numRead = sourceStream.Read(buffer, 0, buffer.Length)) != 0)
            {
                string text = Encoding.Unicode.GetString(buffer, 0, numRead);
                sb.Append(text);
            }

            return sb.ToString();
        }
    }
        );

        await Readfile;

        return Readfile.ToString();

    }

您正在 returnstring,因此将 Readfile 设为 Task<string>:

Task<string> Readfile = Task.Run<string>( ... )

那么你要returnReadfile.Result;,而不是Readfile.ToString();
但是你可以写得更简单:

return await Readfile;

甚至:

return await Task.Run<string>( ... )

您不需要使用 Task.Run 从流中读取,有一个方便的方法 ReadAsync 可以等待:

 public async Task ReadFile() {
      string filePath = @"SampleFile.txt";

      if (File.Exists(filePath) == false) {
        MessageBox.Show(filePath + " not found", "File Error", MessageBoxButton.OK);
      } else {
        try {
          string text = await ReadText(filePath);
          txtContents.Text = text;
        } catch (Exception ex) {
          Debug.WriteLine(ex.Message);
        }
      }
    }

    private async Task<string> ReadText(string filePath) {

      using (FileStream sourceStream = new FileStream(filePath,
          FileMode.Open, FileAccess.Read, FileShare.Read,
          bufferSize: 4096, useAsync: true)) {
        StringBuilder sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0) {
          string text = Encoding.Unicode.GetString(buffer, 0, numRead);
          sb.Append(text);
        }

        return sb.ToString();
      }

    }

也不推荐避免 async void,尽量避免 that.Async void 方法具有不同的 error-handling 语义。当异常从异步任务或异步任务方法中抛出时,该异常将被捕获并放置在任务对象上。使用 async void 方法时,没有 Task 对象,因此从 async void 方法抛出的任何异常都将直接在 async void 方法启动时处于活动状态的 SynchronizationContext 上引发。 Best practice for async methods