c#奇怪的語法

參考微軟網頁:web

使用 Async 和 Await 的異步編程 (C#)
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/index

演練:使用 Async 和 Await 訪問 Web (C#) 
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/walkthrough-accessing-the-web-by-using-async-and-await

await(C# 參考)
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/await

今天作async await實驗時發現一個奇怪的語法現象:編程

static void test()
{
       Console.WriteLine("asyncawaittest");
 }
private void btnasyncawait_Click(object sender, EventArgs e)
 {
       new Thread(test) { IsBackground = true }.Start(); //**注意** IsBackground = true後面沒有分號「;」
       //new Thread(test) { IsBackground = true, Name = "mythreadname" }.Start(); //也成功
 }

以上代碼成功,改爲以下代碼也成功:c#

static void test()
{
       Console.WriteLine("asyncawaittest thread id = "+Thread.CurrentThread.ManagedThreadId+" thread name="+Thread.CurrentThread.Name);
 }
private void btnasyncawait_Click(object sender, EventArgs e)
 {
       Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
       new Thread(test) { IsBackground = true, Name = "mythreadname" }.Start();//**注意**
 }

但在true後面加上一個分號以後出現語法錯誤。後來經過學習才明白這種用法在叫作「對象初始化器」,好比:異步

Person person = new Person();
person.Name = "Slark";
person.Age = 100;
person.Address = "Xi'an";

這裏咱們用了一行建立對象語句,加三行賦值語句。這裏光person這個變量就出現了4遍,繁瑣。用對象初始化器來代替這些操做:

Person person = new Person { Name = "Slark", Age = 100, Address = "Xi'an" };

c#中除了對象初始化器以外,還有集合初始化器:async

List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
好,這裏咱們用4行代碼建立了一個3個元素的集合。集合初始化器的出現大大減小了咱們對這種操做的代碼量。其對應的集合初始化器代碼爲:

List<int> intList = new List<int> { 1, 2, 3 };

下面來真正進入async和await學習中來,先看一段代碼:ide

private void btnasyncawait_Click(object sender, EventArgs e) 
        {
            Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
            Say();
        }
        private async static void Say()
        {
            Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId);
            var t = TestAsync();
            Thread.Sleep(1100);                                     //主線程在執行一些任務
            Console.WriteLine("Main Thread");                       //主線程完成標記
            Console.WriteLine(await t);                             //await 主線程等待取異步返回結果
        }
        static async Task<string> TestAsync()
        {
            return  await Task.Run(() =>
            {
                Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(1000);                                 //異步執行一些任務
                return "Hello World";                               //異步執行完成標記
            });
        }

以上代碼能夠成功運行,點擊按鈕再次,結果以下:異步編程

main thread id = 8
Say thread id = 8
await task thread id = 9
Main Thread
Hello World
main thread id = 8
Say thread id = 8
await task thread id = 9
Main Thread
Hello World

去掉TestAsync()中的async和await即代碼以下時:函數

static  Task<string> TestAsync()
        {
            return  Task.Run(() =>
            {
                Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(1000);                                 //異步執行一些任務
                return "Hello World";                               //異步執行完成標記
            });
        }

代碼也能成功運行,點擊按鈕再次,結果以下:學習

main thread id = 8
Say thread id = 8
await task thread id = 9
Main Thread
Hello World
main thread id = 8
Say thread id = 8
await task thread id = 10
Main Thread
Hello World

當我將代碼修改以下時,發現一個很不明白的現象(主要是將Say()函數中的t以前的await去掉了):測試

private void btnasyncawait_Click(object sender, EventArgs e) 
        {
            Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
            Say();
        }
        private async static void Say()
        {
            Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId);
            var t = TestAsync();
            Thread.Sleep(1100);                                     //主線程在執行一些任務
            Console.WriteLine("Main Thread");                       //主線程完成標記
            Console.WriteLine( t);                             //注意此處t以前沒有await
        }
        static async Task<string> TestAsync()
        {
            return await Task.Run(() =>
            {
                Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(1000);                                 //異步執行一些任務
                return "Hello World";                               //異步執行完成標記
            });
        }

打印出來的結果爲:

main thread id = 10
Say thread id = 10
await task thread id = 11
Main Thread
System.Threading.Tasks.Task`1[System.String]

再將代碼修改以下:

private void btnasyncawait_Click(object sender, EventArgs e) 
        {
            Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
            Say();
        }
        private async static void Say()
        {
            Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId);
            var t = TestAsync();
            Thread.Sleep(1100);                                     //主線程在執行一些任務
            Console.WriteLine("Main Thread");                       //主線程完成標記
            Console.WriteLine( t);                             
        }
        static Task<string> TestAsync()
        {
            return Task.Run(() =>
            {
                Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(1000);                                 //異步執行一些任務
                return "Hello World";                               //異步執行完成標記
            });
        }

打印結果以下:

main thread id = 9
Say thread id = 9
await task thread id = 10
Main Thread
System.Threading.Tasks.Task`1[System.String]

還有一段測試代碼以下:

private void trfun()
        {
            var ttr = Task.Run<String>(() =>
            {
                Thread.Sleep(3000);
                return "abc";
            });
            string rs = ttr.Result;//阻塞3秒
            Console.WriteLine("ttr.result=" + rs);
        }

主程序中調用trfun()函數,則主程序要等待大約3秒鐘以後纔打印出結果abc以後才往下執行。換成以下代碼:

private void btnasyncawait_Click(object sender, EventArgs e) 
        {
            Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
            trfun();            
            Say();
        }
        private async void trfun()
        {
            var ttr = Task.Run<String>(() =>
            {
                Thread.Sleep(3000);
                return "abc";
            });
           
            string rs = await ttr;//當程序執行到此句時不會再向下反而是快速進入btnasyncawait_Click中的Say()
            Console.WriteLine("trfun thread id = " + Thread.CurrentThread.ManagedThreadId);//此句須要等3秒才能執行,且處於主線程ID中
            Console.WriteLine("ttr.result=" + rs);
        }

打印出來的結果以下:

main thread id = 9
Say thread id = 9
await task thread id = 11
Main Thread
Hello World
trfun thread id = 9
ttr.result=abc

這種異步處理對於btnasyncawait_Click及其主線程來講不會阻塞,阻塞的只是trfun中的await ttr語句。

還有一篇帖子 C#Winform裏的async和await異步 http://www.javashuo.com/article/p-bltudvjy-cc.html 講得也不錯

1個按鈕,2個textbox,下面這樣能夠正確異步,窗體也不會死掉,textBox2會先有結果,textBox1再有結果

    private async void button1_Click(object sender, EventArgs e)

        {
            Does();
            textBox2.Text = "1";
        }


        private Task<string> DoWork()
        {
            return Task.Run(() =>
               {
            Thread.Sleep(4000);
            return "Done with work!";
               }
                );
        }
        private async void Does()
        {
            string text = await DoWork();
            textBox1.Text = text;
        }

若是把按鈕事件改爲下面這樣,窗體不會死,但不會異步執行

   private async void button1_Click(object sender, EventArgs e)

        {
            textBox2.Text =await DoWork();
            textBox2.Text = "1";
        }
相關文章
相關標籤/搜索