前言
睽違了兩年之久,
微軟於前幾日正式開放 Visual Studio 2022 Preview1 下載,
雖然平時早已被 Rider 慣壞,但是內心深處對 VS 依舊有愛。
廢話不多說,趕緊來瞧瞧這次的版本多了哪些好料吧!
本次的主題集中在探索內建的程式碼產生功能,
但因為已經一陣子沒接觸 VS 了,
有些提到的功能可能會與 VS 2019 重疊,敬請見諒。

環境準備
首要之務當然是先安裝 Visual Studio 2022!
這邊裝的是 Enterprise 的版本,
語言的部分目前只有提供英文。

接著我選擇安裝 Web 與桌面開發兩種,
使用的空間是 5.9G 多,似乎又輕量了許多(安裝容量忘記截圖 orz)。

安裝的版本是 17.0.0 Preview 1.0,一整個很香阿!

建立 Web API 專案
這個部分跟 2019 的版本並無太大差異,
直接下一步下一步下一步就可以了。

以下的介紹都會反覆使用 Visual Studio 的小燈泡功能(shortcut:Ctrl
+.
)。
建立 Controller
這邊用範本先建一個空的 AccountController
,
範本要記得選 API 的,不然長出來的就會是 MVC 用的 Controller。

長出來的程式碼很陽春,我手動加了一個 Login Action 上去。
糗了,寫完文章才發現 Login
的 Action 不小心掛到 [HttpGet]
,雖然不影響文章內容,不過如果真的要實作登入功能,請記得使用 [HttpPost]
!

新增 LoginService
再來我希望「生」出一個 LoginService,並包含登入檢查的方法。
我在方法中輸入 _
開頭的變數,再按小燈泡快捷鍵,
因為 private filed 預設命名就是底線開頭,
所以 IDE 會知道你要產生的是 field。
按下 Enter 就會自動長出 field 了。

這個不是新功能,在先前使用 VS 的時候就有了。
美中不足的是,IDE 並不讓我把游標移到類別名稱去,
不然應該可以順便把類別也產出來。

不過沒關係,身為宅宅工程師,打幾個字還是可以的。
手動把 object
改為 LoginService
後,
再次觸發小燈泡來產生類別,
這邊我選擇將程式碼產在同個 namespace 下,
一樣按下 Enter 就完成了。

結果如下圖。

Move File (v1)
產完類別後我個人的習慣會先把它搬到其他地方去,
這邊我希望將 LoginService
移動到根目錄的 /Services
底下,
先前 VS 的版本對這部分支援較不友善,不過還是來實驗看看吧!
我將游標移動到 LoginService
旁邊,按下小燈泡快捷。

這邊看到了兩個有關 Move 的選項,
第一個 Move 會將該類別移動到同階層目錄的資料夾內(也就是/Controllers
),
而第二個則是會幫我修改namespace,
很顯然兩個都沒辦法直接幫我建立資料夾。
這邊我選擇先使用第一個 Move 將類別移動到 /Controllers
目錄下,
手動建好 /Services
資料夾後再用滑鼠拉過去。
命名空間修正
因為剛才是從 Controllers 搬過來,
所以命名空間要修正,
將游標移動到 namespace 的 Net6WebApi.Controllers
上,
一樣使用小燈泡快捷,
找到了兩個看起來相符的選項:
- Change namespace to match folder structure
- Change namespaces to 'Net6WebApi.Services'
兩個看起來都符合我的需求,
不過點選第一個的時候觸發了例外錯誤(已回報),
只好改為第二個,點選後命名空間順利修正!

Move File (v2)
原本是快放棄這個功能了,
摸索一陣子發現是有能力可以做到產資料夾的!
步驟如下:
(1) 在上述產類別的步驟中,選用 Generate class 'LoginService' in new file
,這樣會在 /Controllers
下產生獨立的類別檔案(這邊還沒有建立 /Services
資料夾)。

(2) 在類別名稱觸發小燈泡,選擇 Move to namespace
。

(3) 將游標移動到 namespace上,觸發小燈泡後選擇 Move file to 'Services'
。

燈燈,就這樣可以省略建立資料夾的步驟囉!

雖然步驟有點多,但至少手不用離開鍵盤就是了。
這邊有 GIF 的版本,有興趣的朋友可以參考。

產生方法
這個功能應該是之前的版本就有內建了。
我希望可以長出一個 UserLogin
的方法,
並給定 account
及 password
參數。
游標移動到方法名稱後觸發小燈泡,
選擇產生方法即可,

變更方法簽章
接下來,我打算把方法參數的順序做個調整。
將游標移到方法名稱或參數上,觸發小燈泡後選擇 Change signature
。

接著就可以透過介面操作把 account
移到前面來,
這個畫面…好像似曾相似阿xD


呼叫端的參數順序也會自動調整。

提取變數
接著我們將鏡頭拉回到 LoginService
,
我想要宣告一個 isAdmin
的布林變數,
檢查 account
是否為 Roberson
。
先打完結果之後,嘗試了一下 .var
ㄉ的 post template,
不過看起來並不支援。

接著改用小燈泡快捷,發現 Introduce local for '…'
的選項,
看來這跟 JetBrains 家的 Introduce variable
是相同的效果。

就這樣,變數也順利產出來了!

Explicit / Impicit 型別轉換
接著我想要把變數宣告從 Explicit 轉成 Implicit 的 var
,
VS 一樣能幫我們做!
只要把游標移到變數開頭就可以了。

當然,需要的話你也可以轉回去!

神奇的 IntelliCode
這個功能官方宣稱是使用最潮的 AI 來判斷,
可以根據當前程式碼的 context 自動幫你補 code,
官方說這次的版本針對 IntelliCode 的部分有做強化,
使用起來算是還不錯的體驗,
希望有朝一日大家都可以按 Tab
寫扣就好xD
IntelliCode 發揮作用時會跑出淺灰色的 Hint,
如果跑出來跟你想寫的是一樣的,
就把 Tab
大力按下去就是了!
(目前不知道什麼時機會被觸發。)
下圖是在使用 if
的時候觸發的。

按下 Tab
後就會自動補齊程式碼啦~

自動產生括號
當然,括號也可以用產的。
只要把把游標移動到 if
附近,
觸發小燈泡,就可以直接補上尖尖的括號(braket)啦~

Fix return type
現在方法還是 void
,
我希望在 if
條件成立時回傳 true
,
不過這段沒辦法用產的,先手動補上。

接著把游標移動到 return
的 statement 裡面,
一樣觸發小燈泡,點選 Fix return type
。

點選之後,就會幫我們修改回傳型別。
有點可惜的是,下面那行 throw
實際上不會執行到了,
但卻沒辦法使用小燈泡移除掉。

接著手動移除掉 throw
的部分,
在下方補上 return 的過程再次觸發 IntelliCode!

Extract Method
接著我想將 isAdmin
變數判斷的部份抽成方法。
這邊必須使用游標將整段程式碼都選取起來,
原本嘗試用 Ctrl+W
向外選取的方式,
不過選到第一層就不能再往外選了,
只好改用 Home+Shift+End
。

結果如下圖。

可以 Extract 當然也可以 Inline。
但是游標必須移動到呼叫端才叫用的到,
也就是說如果有多個程式端呼叫同一個方法時,
沒辦法一次 Inline 回去。
這邊提供兩個 Inline 的選項,
第一個是直接 Inline ,第二個是 Inline 但不保留方法。

在測試時有發現一個問題,如果有多個程式端呼叫同一個方法,這時用第一個方式直接 Inline 會造成呼叫端找不到方法參考。
Inline temporary Variable
接著我想把剛才的 isAdmin
變數 Inline 回 if
內,
游標必須移動到變數宣告的地方,叫出小燈泡就能看到選項。

Convert to conditional expression
先來看一下現在的 UserLogin
方法,
有沒有覺得哪邊有點多餘?

看出來了吧!
if
那段可以縮減成直接 return
,
不過先不要急著打字!
我們把游標移到 if
裡面,呼叫小燈泡~

然後點選 Convert to conditional expression
,
聰明的 VS 就會幫你改好了!

Remove parameter
到目前為止,都沒有用到 password
這個方法參數,
所以我想直接把它刪掉。
作法是叫出前面提過的 Change Signature
。

選取 password
之後再點選 Remove
就可以了。

按下 OK 之後沒用到的 password
就會被移除。

當然,呼叫方也會一併修改。

Use expression body for methods
最後,我們可以再將方法轉換成 lambda 箭頭的形式。
將游標指到括號的部分,觸發小燈泡即可。


結語
目前體驗下來,我覺得官方這次端出的 VS 2022 真的算是很有誠意!
除了速度上明顯與之前的版本優越許多(64-bits )之外,
在程式碼產生的功能也越來越完善,這是好事。
雖然跟 JetBrains 家的產品比起來,還是會有落差。
但是妥善利用這些功能,相信還是可以提升不少的生產力的。
如果想要變得更快的話,
我個人很推薦 91 哥的極速開發實體課程,
有興趣的朋友可以參考課程連結,
這梯次已經額滿了,
不過後面會推出線上直播的版本(搭配免費回鍋實體課程)。
文章內容如有勘誤,還請告知。