天天看點

【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的設計基石

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

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

關于代碼的執行流程那得自個兒看看,慢慢跟着執行流程,相信就能明白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再次調用,就完成了全部的請求處理了。

小總結

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

生活本身是很艱難,但是不能成為你不努力的借口!

Remember, Hope is a good thing, maybe the best of things and no good thing ever dies !

繼續閱讀