C# 正确使用async和Wait
我刚刚开始讨论c#中的异步编程,我开始阅读异步方法并等待 在下面的这段代码中,WPF应用程序接收用户的输入,将其保存到Bin目录中的文件中,并将其读回文本框。我必须使用C# 正确使用async和Wait,c#,async-await,C#,Async Await,我刚刚开始讨论c#中的异步编程,我开始阅读异步方法并等待 在下面的这段代码中,WPF应用程序接收用户的输入,将其保存到Bin目录中的文件中,并将其读回文本框。我必须使用async方法进行读写,但我还需要在WriteText和ReadText方法中的方法中实现wait 你能给我一个简短的解释,说明我应该如何在这段代码中实现async和Wait的使用吗 public partial class MainWindow : Window { public MainWindow() {
async
方法进行读写,但我还需要在WriteText
和ReadText
方法中的方法中实现wait
你能给我一个简短的解释,说明我应该如何在这段代码中实现async和Wait的使用吗
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void btnWriteFile_Click(object sender, RoutedEventArgs e)
{
await WriteFile();
}
private async void btnReadFile_Click(object sender, RoutedEventArgs e)
{
await ReadFile();
}
public async Task WriteFile()
{
string filePath = @"SampleFile.txt";
string text = txtContents.Text;
Task task1 = new Task( () => WriteTextAsync(filePath, text));
}
private async Task WriteTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Create, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true))
{
//sourceStream.BeginWrite(encodedText, 0, encodedText.Length);
await ?? sourceStream.BeginWrite(encodedText, 0, encodedText.Length, null, null);
};
}
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))
{
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();
}
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
私有异步无效btnWriteFile\u单击(对象发送方,路由目标)
{
等待WriteFile();
}
私有异步无效btnReadFile_单击(对象发送方,路由目标)
{
等待ReadFile();
}
公共异步任务WriteFile()
{
字符串filePath=@“SampleFile.txt”;
string text=txtContents.text;
Task task1=新任务(()=>WriteTextAsync(文件路径,文本));
}
专用异步任务WriteTextAsync(字符串文件路径,字符串文本)
{
byte[]encodedText=Encoding.Unicode.GetBytes(文本);
使用(FileStream sourceStream=newfilestream(filePath,
FileMode.Create,FileAccess.Write,FileShare.None,
bufferSize:4096,UseAync:true)
{
//sourceStream.BeginWrite(encodedText,0,encodedText.Length);
wait??sourceStream.BeginWrite(encodedText,0,encodedText.Length,null,null);
};
}
公共异步任务ReadFile()
{
字符串filePath=@“SampleFile.txt”;
if(File.Exists(filePath)==false)
{
显示(文件路径+“未找到”,“文件错误”,MessageBox按钮.OK);
}
其他的
{
尝试
{
字符串文本=等待读取文本(文件路径);
txtContents.Text=文本;
}
捕获(例外情况除外)
{
Debug.WriteLine(例如消息);
}
}
}
专用异步任务ReadText(字符串文件路径)
{
使用(FileStream sourceStream=newfilestream(filePath,
FileMode.Open,FileAccess.Read,FileShare.Read,
缓冲区大小:4096)
{
StringBuilder sb=新的StringBuilder();
字节[]缓冲区=新字节[0x1000];
国际货币联盟;
while((numRead=sourceStream.Read(buffer,0,buffer.Length))!=0)
{
string text=Encoding.Unicode.GetString(缓冲区,0,numRead);
附加(正文);
}
使某人返回字符串();
}
}
}
FileStream类具有读取和写入流的异步方法:ReadAsync
和WriteAsync
,因此您只需在代码中交换这些方法,并在它们前面加上wait:
private async Task<string> ReadText(string filePath)
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096))
{
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/await:
private async Task<string> ReadText(string filePath)
{
return await Task.Run(() =>
{
return File.ReadAllText("textfilepath.txt");
});
}
private async Task ReadText(字符串文件路径)
{
返回等待任务。运行(()=>
{
返回File.ReadAllText(“textfilepath.txt”);
});
}
FileStream类具有读取和写入流的异步方法:ReadAsync
和WriteAsync
,因此您只需在代码中交换这些方法,并在它们前面加上wait:
private async Task<string> ReadText(string filePath)
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096))
{
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/await:
private async Task<string> ReadText(string filePath)
{
return await Task.Run(() =>
{
return File.ReadAllText("textfilepath.txt");
});
}
private async Task ReadText(字符串文件路径)
{
返回等待任务。运行(()=>
{
返回File.ReadAllText(“textfilepath.txt”);
});
}
让我们一次只取一个:
public async Task WriteFile()
{
string filePath = @"SampleFile.txt";
string text = txtContents.Text;
Task task1 = new Task( () => WriteTextAsync(filePath, text));
}
task1在这里做什么?您需要实际运行它并等待它:
public async Task WriteFile()
{
string filePath = @"SampleFile.txt";
string text = txtContents.Text;
Task task1 = new Task( () => await WriteTextAsync(filePath, text));
await task1;
}
但是等等!我们正在创建一个任务
,它创建一个任务
,然后等待该任务
。为什么不首先返回任务
public Task WriteFile()
{
string filePath = @"SampleFile.txt";
string text = txtContents.Text;
return WriteTextAsync(filePath, text);
}
记住,async
使我们更容易创建在任务
中执行某些操作的方法,但是如果您已经有了任务
,那就是浪费时间
另外,按照惯例,您应该将异步方法的名称命名为Async
。这里更是如此,因为您与其他WriteTextAsync
的区别仅在于签名:
public Task WriteTextAsync()
{
return WriteTextAsync(@"SampleFile.txt", txtContents.Text);
}
实际上,这与使用非异步void WriteText(string filePath,string text)
时如何从非异步void WriteText()调用它没有什么不同。这里没有什么新鲜事
现在,我们来谈谈更复杂的WriteTextAsync
:
private async Task<string> ReadText(string filePath)
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096))
{
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();
}
}
private async Task<string> ReadText(string filePath)
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096))
{
using(var rdr = new StreamReader(sourceStream, Encoding.Unicode))
{
return await rdr.ReadToEndAsync();
}
}
}
因为我们现在有了任务,我们根本不需要使用旧的BeginWrite
(见下文),我们只需要使用WriteAsync
,就像我们使用Write
一样:
private async Task WriteTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Create, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true))
{
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}
}
ReadFile()
可以。让我们看看它对以下内容的调用:
private async Task<string> ReadText(string filePath)
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096))
{
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();
}
}
对于非异步版本,一个更好的整体解决方案是使用ReadToEnd()
,该解决方案更简单、更具弹性,可以使用ReadToEnd()
。同样,这里更好的版本是使用ReadToEndAsync()
:
以及:
private async Task ReadText(字符串文件路径)
{
使用(FileStream sourceStream=newfilestream(filePath,
文件模式。打开,文件访问
private async Task<string> ReadText(string filePath)
{
using(FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize:4096))
{
StringBuilder sb = new StringBuilder();
byte[] buffer = new byte[0x1000];
int numRead;
while((numRead = await Task<int>.Factory.FromAsync(sourceStream.BeginRead, sourceStream.EndRead, buffer, 0, buffer.Length, null)) != 0)
{
sb.Append(Encoding.Unicode.GetString(buffer, 0, numRead);
}
return sb.ToString();
}
}