使用任务在 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
我开始学习异步编程,我偶然发现了这个问题。我通过 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