在Visual Studio發佈以來,新增了大量的功能,其中最讓我感到欣喜的是C#新增的利用async標識符和await相結合使用進行異步編程,固然,遺憾的是,此功能只支持WinForm和WPF程序。 web
使用 async 功能,您能夠調用異步方法,而不定義持續性任務或經過多個方法或 lambda 表達式拆分代碼。其實,仔細想一想,其底層應該是封裝了開闢新線程、調用和回調的操做! 編程
回想下,在先前的WinForm和WPF的同步編程,好比咱們在當前UI下進行一個很是耗時的操做的時候,窗體的表現是不能隨意拖動和關閉的,必須等待當前的操做完成以後,才能執行其餘的操做,給用戶的體驗很是差。在之前的版本中,要實現異步操做,必須手動去啓動窗體的UI線程容許跨進程調用的開關,而且把須要進行異步操做的代碼寫在一個委託中,而後手動的去新開線程,來完成異步的操做。 windows
而後,新版的Visual C#封裝了這些麻煩的操做,讓咱們進行異步編程變得很是的簡單。只須要利用async和await相結合使用,就能夠輕鬆的異步編程。 app
在下面的兩個例子中,將詳細的講述如何利用async和await來進行異步編程。 異步
第一個例子,是一個簡單的WPF程序,其主要功能是異步去請求幾個URL,並獲得這些資源的字符個數,而後輸出在相應的文本框中。 async
新建一個WPF應用程序,添加一個按鈕和文本框,文本框多行顯示。給按鈕註冊一個異步的Click方法。標誌按鈕的Click事件是一個異步方法,只須要添加標示符async。 異步編程
private async void startButton_Click(object sender, RoutedEventArgs e)
{
resultsTextBox.Clear(); this
await SumPageSizesAsync(); url
Task sumTask = SumPageSizesAsync();
await sumTask; spa
//上面的兩句話等價於:await SumPageSizesAsync();
resultsTextBox.Text += "\r\nControl returned to startButton_Click.\r\n";
}
private async Task SumPageSizesAsync()
{
//.Net Framework4.5中新增了一個新的類HttpClient,這個類封裝異步web操做,很是的牛B
//固然咱們也能夠用傳統的WebRequest和HttpWebRequest類。
HttpClient client = new HttpClient();
List<string> urlList = SetUpURLList();
var total = 0;
foreach (var url in urlList)
{.
byte[] urlContents = await client.GetByteArrayAsync(url);
//上面的一句話等價於下面的兩句話
//Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
//byte[] urlContents = await getContentsTask;
DisplayResults(url, urlContents);
total += urlContents.Length;
}
resultsTextBox.Text +=
string.Format("\r\n\r\nTotal bytes returned: {0}\r\n", total);
}
private List<string> SetUpURLList()
{
List<string> urls = new List<string>
{
"http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
"http://msdn.com",
"http://msdn.microsoft.com/en-us/library/hh290136.aspx",
"http://msdn.microsoft.com/en-us/library/ee256749.aspx",
"http://msdn.microsoft.com/en-us/library/hh290138.aspx",
"http://msdn.microsoft.com/en-us/library/hh290140.aspx",
"http://msdn.microsoft.com/en-us/library/dd470362.aspx",
"http://msdn.microsoft.com/en-us/library/aa578028.aspx",
"http://msdn.microsoft.com/en-us/library/ms404677.aspx",
"http://msdn.microsoft.com/en-us/library/ff730837.aspx"
};
return urls;
}
private void DisplayResults(string url, byte[] content)
{
// Display the length of each website. The string format
// is designed to be used with a monospaced font, such as
// Lucida Console or Global Monospace.
var bytes = content.Length;
// Strip off the "http://".
var displayURL = url.Replace("http://", "");
resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
}
有關HttpClient和Task、Task<TResult>請參考MSDN。
編譯WPF應用程序,在程序異步執行請求操做的時候,你能夠隨意的拖動窗口或者隨時均可以關閉窗口,是否是以爲很方便,體驗也很爽。想了解更詳細的信息,告訴你一個祕籍,趕忙看MSDN,而且撞上windows8和Visual Studio2012開始你的奇妙之旅吧。
第二例子是文件I/O的異步操做,下面的例子包括了異步讀取操做、異步拷貝操做、異步寫操做。更多地文件I/O異步操做,建議你放看MSDN。
新建一個WinForm程序,添加三個按鈕,來分別執行異步讀取操做、異步拷貝操做、異步寫操做。
在上面的WPF例子中,講述瞭如何爲按鈕註冊一個異步事件。就是用async標示Click事件。
//異步讀
private async void btnReadAsync_Click(object sender, EventArgs e)
{
string sourceDir = @"C:\個人文件夾";
this.txtContentsByReadAsync.Clear();
foreach (string item in Directory.EnumerateFiles(sourceDir))
{
string fileContents="";
using (StreamReader sr=File.OpenText(item))
{
fileContents= sr.ReadToEnd();
}
using (FileStream stream=File.Open(item, FileMode.Open))
{
byte[] buffer=new byte[stream.Length];
int num= await stream.ReadAsync(buffer, 0, buffer.Length);
this.txtContentsByReadAsync.Text += string.Format("讀取了{0}個字節\r\n,文件的內容爲:\r\n{1}", num.ToString(), fileContents);
}
}
}
//異步拷貝
private async void btnCopyToAsync_Click(object sender, EventArgs e)
{
string startDir = @"C:\個人文件夾";
string destinationDir = @"C:\個人文件夾\新建文件夾\";
foreach (string item in Directory.EnumerateFiles(startDir))
{
using (FileStream fileStream=File.Open(item, FileMode.Open))
{
using (FileStream Stream=File.Create(destinationDir+item.Substring(item.LastIndexOf('\\'),item.Length-item.LastIndexOf('\\'))))
{
await fileStream.CopyToAsync(Stream);
}
}
}
}
//異步寫
private async void btnWriteAsync_Click(object sender, EventArgs e)
{
string sourceDir = @"C:\個人文件夾";
foreach (string item in Directory.EnumerateFiles(sourceDir))
{
using (StreamReader reader=File.OpenText(item))
{
using (StreamWriter writer=File.CreateText(sourceDir+"\\"+"新建文件夾"+"\\"+"複製文件"+item.Substring(item.LastIndexOf('\\')+1)))
{
await CopyFilesAsync(reader, writer);
}
}
}
}
private async Task CopyFilesAsync(StreamReader reader, StreamWriter writer)
{
char[] buffer = new char[0x1000];
int num;
while ((num = await reader.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
await writer.WriteAsync(buffer, 0, num);
}
}
從上面的例子中能夠看出,進行文件的異步I\O操做已經變得如此簡單。
注意,要使用await異步編程,代碼必須放在aysnc標識符標識的異步方法內部。對於控件的事件,只須要用async來標識便可。對於普通的方法,若是方法的返回值爲空或者null的時候,用async和task一塊兒標識該方法是無返回值的方法,對於返回泛型類型的方法來講,用async和task<T>來同時標誌方法是異步方法,其中T爲返回的類型。
上面的WPF例子用到了.Net Framework提供的新的類HttpClient,要使用這個類,程序中必須引用組件:
System.Net.Http組件。