【C# in depth 第三版】溫故而知新(1)


聲明


本文歡迎轉載原文地址:http://www.cnblogs.com/DjlNet/p/7192354.html


前言


關於這本書(《深入理解C# 第三版》)的詳細情況以及好壞,自行搜索即可,我就不啰里啰嗦的,此文責在備份,意在記錄一下第二次閱讀當中發現原先囫圇吞棗之處,也為了記憶深刻吧。對這里還有一本《Clr via C# 第四版》也准備二次閱讀,關於精度細讀章節,知乎傳送門( 趙姐夫的回答 ): https://www.zhihu.com/question/27283360。就在昨天(9月9號)北京和上海相繼展開了技術分享會(有同步直播),這里要給北京的sqlserver演講的老哥點贊,講得不錯挺落地和實在的,還有上海的分享的【.Net 微服務實戰】,看了心里挺有感觸的,並不是說從知識或者實踐的層面領悟到有多少有多少,而是理解和明白這玩意兒為何而生,培養一點大局觀和思維套路吧,畢竟在DDD、微服務大行其道的今天只有不斷學習,然后溫故而知新,可能才能知道它們想表達的含義吧!


這些知識你還記得么嗎,\(^∀^)メ


上面扯了一些口水話,其實在學習偏架構的知識時候,那么必經之路便是對語言基礎的足夠掌握以及對上層框架的理解掌握,那么今天再去扯架構和框架之前就來回顧一下關於語言的一些小知識,以下是在下記錄一些書中查漏補缺自個人備份記憶使用,其中可能也包含以下不常用或者小知識,大神大佬請自動忽略 ,哈哈。


誤區:對象在C#中默認是通過引用傳遞的

我這里摘錄引用書中部分描敘:首先“引用傳遞”的正式定義相當復雜,要涉及左值和類似的計算機科學術語,但是最重要的一點是,假如以引用傳遞的方式來傳遞一個變量,那么調用的方法可以通過更改其參數值,來改變調用者的變量值(說到這里有木有想到 ref out 關鍵字,是的它們就可以達到引用傳遞的效果)。那么默認情況,就是沒有顯示使用關鍵詞的情況,引用類型變量的值才是引用(類似: 0x12345678 這種),而不是對象本身,且不需要按引用來傳遞參數本身,就可以更改該參數引用的那個對象的內容。例如:下面的方法更改了相關對象StringBuilder的內容,但是調用者的表達式引用的仍然是之前的那個對象:

void AppendHello(StringBuilder builder)
{
    builder.Append("Hello");
}

調用這個方法時,參數值(對StringBuilder的一個引用)是以值傳遞的方式傳遞的。如果想在方法內部更改builder的變量值,如:builder=null;對調用者來說是看不見的。


理解:JIT編譯器如何處理泛型

對於所有的封閉類型,JIT的職責就是將泛型類型的IL轉換為本地代碼,我們以List 作為例子,首先JIT為每個以 值類型作為類型實參的封閉類型都創建不同的代碼,理論上對於一些值類型來說,代碼是可以共享的,但是JIT必須十分謹慎,不僅需要考慮空間大小的問題,還要考慮垃圾回收的問題,所以第一次創建獨享的代碼。那么,所有使用引用類型(string、stream、stringbuilder等)作為類型實參的封閉類型都共享相同的本地代碼,之所以可以這樣做,是由於 所有引用都具有相同的大小(32位CLR上是4個字節,64位CLR是8個字節,在任何一個特定的CLR中所有引用具有相同的大小)。關於泛型的新增API, GetGenericTypeDefinition作用於已構造的類型,獲取它的泛型類型定義和 MarkGenericType作用於泛型類型的定義,返回一個已構造類型,諸如此類還有: GetGenericArguments、IsGenericTypeDefinition、IsGenericType、MarkGenericMethod、IsGenericMethod等等。


Nullable 類型理解與使用null進行賦值和比較原理

注意Nullable 是一個結構也就是 值類型,對於例如Nullable 的變量來說,直接包含了一個bool和一個int成員,而不是其他對象的引用。關於null賦值比較,原理:C#編譯器允許使用null在比較和賦值時表示一個可空類型的空值。其中這樣來處理的原因,相信也是從語言層面讓語義更加符合自然邏輯,獲得和引用類型null的同樣體驗。那么到底編譯器關於可空值類型幫我們做了什么吶, int? a=null; if(a==null){ .... },與null比較其實在編譯器生成IL代碼中,被轉換為調用 a.HasValue,對a賦值為null,其實也是調用了Nullable 的構造函數創建一個空值實例而已,注意直接調用a.Value在沒有真正的值提供時將會拋出異常。


注意匿名函數變量捕獲

划重點:
1、捕獲的是變量本身,而不是創建委托實例時它的值
2、捕獲的變量的生存周期被延長了,至少和捕獲它的委托一樣長
3、多個委托可以捕獲同一個變量
4、在循環內部,同一個變量聲明實際上會引用不同的變量“實例”(這點在R#也會提示開發者)
5、如果捕獲的變量不會發生改變,就不需要擔心
6、在C#5或者以上修正foreach的表達含義,但是for依然需要注意。


理解Yield的工作流程和成為奠定異步Async/Await的設計基石

這里直接引用書中的代碼加強記憶和再次熟悉下流程,如下圖所示代碼:

關於代碼的執行流程那得自個兒看看,慢慢跟着執行流程,相信就能明白Yield在代碼執行中起到的作用,就貌似能在不同的方法之間跳躍,總的來說可以歸為幾點:
1、在第一次調用MoveNext之前,CreateEnumerable中的代碼不會被調用
2、所有工作在調用MoveNext時就完成了,獲取Current的值不會執行任何代碼
3、在yield return的位置,代碼會停止執行,方法暫時返回調用者方法,在下一次執行MoveNext時有繼續在下一行代碼繼續執行
4、在一個方法中的不同位置可以編寫多個yield return語句
5、代碼不會在最后的yield return處結束而是通過返回false的MoveNext調用來結束方法的執行
上面說了這么多,在看到第3和4點的時候有沒有感覺到await的部分作用似曾相識,await也可以讓方法返回而且可以等在那里等到結果拿到之后接着那個“斷點”繼續執行,而且在一個Async標記的異步方法中可以,有多個await的拆包操作,所以在一定程度上面yield在思想和設計層面上,給后面的C#5的異步埋下了鋪墊。從狀態機的角度來看(這塊並不是很熟悉,所以說錯了,請斧正)在C#5中為迭代器塊而生成的狀態機和那些異步函數而生成的狀態機之間的相似性是驚人的。異步開發中兩個復雜的問題就是:1、處理狀態 2、在感興趣的事情發生之前進行有效的暫停,迭代器使得這兩個問題得以完美的解決。 這里提供一下yield實現異步的偽代碼,也是書中的代碼片段:(偽代碼是基於CCR實現的,主要是明白它想傳遞表達的意思,即可代碼部分看看就好)

static IEnumerator<ITask> ComputeTotalStockVal.(str.user,str.pass)
{
        string token=null;
        yield return Arbiter.Receive(false,AuthService.CcrCheck(user,pass),
            delegate(string t){ token=t; });
        IEnumerable<Holding> stocks=null;
        IDictionary<string,decimal> rates=null;
        yield return Arbiter.JoindReceive(false,
            DbService.CcrGetStockHoldings(token),
            StockService.CcrGetRate(token),
            delegate(IEnumerable<Holding> s,IDictionary<string,decimal> r)
            {
                stocks=s;
                rates=r;
            });
        OnRequestComplete(ComputeTotal(stocks,rates));
}

大致對上面代碼做個解釋說明雖然是偽代碼,CCR對我們的代碼進行了調用也就是調用MoveNext,第一個yield return才會執行,AuthService里面的CcrCheck方法啟動一個異步請求,CCR會等待直到它完成,然后提供給它的委托來處理拿到的結果也就是token,然后接着再次調用MoveNext,方法接着執行,JoindReceive並行啟動兩個異步請求,在兩個請求都完成的情況下,利用后續的委托去處理結果,在這之后MoveNext再次調用,就完成了全部的請求處理了。


小總結

再回看一些基礎知識的時候,才發覺原來語言層面的設計不比一些高層架構的設計的重要性和觀賞性差(雖然沒什么可比性,哈哈),好了,天不早了,后面應該會出續篇,等這個完了之后,應該會開始對一些大家關注的點出發,腳踏實地的從代碼、需求和設計層面考慮去寫一些可使用的代碼片段或者程序設計,用作以后參考或者借鑒。最最后,好好給自己一記耳光,咋就做人真懶吶,看看離上次發文都多長時間了,送給自己的話:從現在起做一個不那么懶的人吧!謹記!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM