跳到主要內容

C# 泛型

為什麼要使用泛型Generic

這次要提到的是泛型,也是這次我負責上課的部分。
我會就自己的吸收用自己的理解來說明什麼是泛型。
泛型簡單的說就是 C# 2.0 提出的一種新的集合類別,用於汰換掉 .NET 1.1 的非泛型集合類別。

以 List<T> 為例子,就是拿來汰換掉 ArrayList 用的。
以前 ArrayList 提出也是為了解決某些問題而發明出來的類別,主要是解決程式碼重複的問題。 為了儲存 int 需要設計一個儲存 int 的集合類別,為了儲存 string 需要一個儲存 string 的集合類別。 所以不如設計一個 ArrayList 可以儲存 int 也可以儲存 string 。這是怎麼做到的呢?
原理就是因為型別都是來至於 object ,因此只要將所有型別的先轉換成 object 存起來,然後要用的時候再取出來,然後從 object 轉型回原本儲存的型別就好,這就是 ArrayList 。

講完 ArrayList,來說說 List<T> ,泛型是在實例化的時候確定使用的型別,以便於在編譯時期就可以判斷型別安全性,也因此帶出泛型與 ArrayList 比較後的優點。可以讓編譯器來保護程式碼。至於程式碼重複這個優點泛型跟 ArrayList 一樣都有,另外還有一個 優點,那就是效能。 ArrayList 出了什麼問題呢? 最主要的問題就是轉型,因為儲存成 object ,存入時跟取出時都需要做轉型,這稱為 Boxing / UnBoxing,從 int 轉型成 object 稱為 Boxing;反之從 object 轉成 int 就是 UnBoxing了,這耗費效能。但 List<T> 因為在實例化的時候就指定好型別的,因此沒有這個問題。

以上三個好處,程式碼重複使用、型別安全性、效能,就是以泛型集合類別取代非泛型集合類別的好處。

留言

這個網誌中的熱門文章

[學習iOS之路] Lifecycle 比較

在開發Android很多年之後終於開始學習寫iOS了 契機就是工作需要,果然工作需求就是推開最大靜摩擦力的原動力啊! 在這邊寫下學習Swift的一些筆記,希望在自己忘記或是需要給別人教學的時候可以起到一點點作用。 因為對Android比較熟悉,所以透過比較來熟悉iOS架構 首先是iOS與android的比較 可以參考這張圖 Android vs iOS lifecycle 與這張 iOS 詳細state 流程 Android lifecycle OnCreate -> OnStart -> OnResume ->(running) -> OnPause -> OnStop -> OnDestroy                        ^                  ^                                  |               |                         |                  |-------------------v               |                         |-----<-----   OnRestart   ------<---------v iOS lifecycle LoadView -> ViewDidLoad -> ViewWillAppear -> ViewDidAppear -> (running) -> ViewWillDisappear -> ViewDidDisappear -> ViewWillUnload -> ViewDidUnload -> dealloc 於ViewDidDisappear之後view就看不見了,如果view要再次被看到且view還存在 那就會是ViewWillAppear,否則就是LoadView從頭開始 下一篇是語言的比較 Java vs Swift

Docker vs VM 的學習

工作上用到 Docker 也一段時間了,剛接觸到 Docker 時常常會聽到別人這樣解釋," Docker 的 Container 技術,類似於 VM 。差別是 Container 比較小,沒有包含 OS,而 VM 會包含 OS"。 這段話我覺得不算是全錯,所以我一開始也是這樣去解釋給別人聽,直到我聽到我同事在面試求職者時問了這句話,"如果 Container 比較快,比較輕量,優點這麼多,為什麼 VM 沒有被淘汰?" 我才忽然意識到,我並沒有真正瞭解這兩種技術的差別。 事實上,這件事情要從解決問題的角度上出發去理解。任何技術的產生應該都是為了解決某些痛點,從這點來思考的話網路上就有很多文章可以查到了,我把我查到的最清楚的文章連結放下本文最下方,有興趣的可以去看看。 VM 是為了解決硬體的資源共享的問題所產生出來的技術,而這個需求仍然存在,並不會因為有了 Docker 的 Container 技術就取代了。這個可以回答為什麼 VM 沒有被淘汰。因為要解決的問題不一樣,事實上很多 Container 還是跑在 VM 裏頭,可謂是相輔相成。 那 Docker 是為了解決什麼問題才發明的呢? 我的消化與理解是 "解決建置環境的複雜度" 而發明的,每個 Dockerfile 會指定使用的映象檔(image),然後寫下需要安裝的 Tool 指令。按照這個 Dockerfile 上面列下的指令去安裝與建置,就可以重現執行這個 APP Runtime 所需要的環境。這解決了以前工程師常說的那句話 "在我的電腦上跑得好好的,為什麼在正式環境就行不通" 的問題。   參考連結

C# CSRF attribute 的錯誤追蹤與處理

最近開發網站碰到一個問題,有時候可以登入成功,有時候不行。但明明帳密都是 Google 記憶的,不可能打錯帳號密碼。後來猜想到是 CSRF 認證的問題,由於網站是透過 k8s 建立的,且 replicas: 2。很大可能性是因為拿 token 是跟 A Pod 拿,但登入是跟 B pod 登入,造成 token 無法驗證成功。 想證明這個問題,我們必須去紀錄 Log,由於我們是透過 C# 的 ValidateAntiForgeryToken Attribute 實作 CSRF 的防禦,因此一開始想法是寫一個 ExceptionFilter 去攔截例外。但發現無法攔截 CSRF 的問題。後來找了一段時間發現,CSRF 並不是丟出例外,而是結果回覆 HttpStatusCode 400。查到可實作 IAlwaysRunResultFilter 攔截結果,並判斷是否是 IAntiforgeryValidationFailedResult 的一種。 程式碼如下:  public void OnResultExecuting(ResultExecutingContext context) { if (context.Result is IAntiforgeryValidationFailedResult result) { // Log here } } 但是這樣還不夠。還必須要強制關閉客戶端錯誤的轉換才行,這樣才可以精準的把結果視為 IAntiforgeryValidationFailedResult 至於怎麼關閉則是在註冊 MVC 服務的時候設定 Config SuppressMapClientErrors = true 即可。      services.AddMvc().ConfigureApiBehaviorOptions(options => { options.SuppressMapClientErrors = true; }); 詳細可以參考 MSDN