RoslynPad 初探

  • 1498
  • 0
  • 2021-09-16

把 C# 腳本化,變成一種輕量的可執行文件,在細碎的小任務中,只要一個文字檔,上面只有必要的 Code,這種簡潔 LINQPad 做到了,行動力也大大提升。

但在推廣 LINQPad 的路上,最大的難點就是 FREE 版真是太難用了,寫 .NET 沒有 IntelliSense 就像閉著眼睛走路。

這時我注意到了 RoslynPad,一個同樣能編寫 C# 腳本的 .csx 輕量開源測試工具。

.csx 最早應該是 VS2015 上市時,附帶的 csi.exe REPL 互動式介面所使用的腳本。後來看中 .csx 格式的腳本特性,並為其製作的開源工具就不斷冒出,也各自做了一些語法上的擴充。

而 RoslynPad 則是少數有配置豐富 UI 並有 IntelliSense 支援的工具。

安裝

可到 GitHub 下載免安裝執行檔(連結),下載紅框的 zip 檔解壓縮即可。

也可從 Microsoft Store 安裝(連結)

安裝完用 "Hello World" 測試,棒棒的,只用一行就完成了。

功能

有一些功能目前只有快速鍵,沒有 UI 按鈕,其實可以理解 UI 不是加一個按鈕那麼簡單,自然優先度就比較低。

*代碼校正(Code Fixes):Ctrl + .  

就是 VS 的小燈泡功能,自動為當前物件補上命名空間(重要)、自動補完 new 物件左邊變數等等的,也可以用滑鼠點,但手不用離開鍵盤更帥。

*列出成員(Member):Ctrl + Space 

這個功能對寫 .NET 的人來說很重要,但快速鍵就看個人了,因為按倒退鍵把字重打也可以重新叫出成員清單。

小心輸入法吃鍵,這個快速鍵組合剛好會被中文輸入法吃掉。

復原 / 重做Ctrl + Z / Ctrl + Y。和 VS 一樣有超長的記錄可以回放。

*尋找 / 取代Ctrl + F / Ctrl + H

以上做了星號(*)標記的功能,它們的快速鍵在 UI 上都找不到,所以特別標起來。

可使用 NuGet:關鍵字 #r  

這功能也很重要,現在寫 .NET 幾乎離不開 NuGet。在這 NuGet 或本地 dll 都是一種參考,RoslynPad 在這塊的提示功能寫地還蠻友善的。

使用評估

主要是取一些用我日常會 LINQPad 完成的事來試用 RoslynPad 看感覺如何。

快速啟動

很快,大約 0.5 秒,LINQPad 則要約兩秒。

字串處理

剪貼文字到字串變數進行處理(如 JSON, CSV 等),遇到有逸出字元,如 C# 最棘手的應該就是有雙引號的狀況,LINQPad 有 'Paste as Escaped String' 快速解決,RoslynPad 就比較陽春了。

不過還是有解,不好用貼的,存成文字檔就好,或許也可以裝個 Wox(連結) 加個擴充來處理字串。 

引用

RoslynPad 引用 NuGet 還蠻方便的,不過沒有 Description、Author、Downloads 可以參考,無法做簡易的瀏覽,如果是不熟的 package 就比較難做判斷,可能要另外上 nuget.org 去查看

dll 引用有路徑自動完成,還算順手。但要是可以像 LINQPad 一樣拖曳 dll 進視窗來完成就更棒了。

備份和分享

.csx 檔 vs .linq 檔,都很好備份及分享。LINPad 的資料庫連線資訊是另外存在本機並加密的,分享檔案不用特別抹去連線帳密。

RoslynPad 雖然沒有設計儲存資料庫連線的機制,但可以自己增設像是 Common.csx 用 #load Common.csx ,分享時不要給這個檔就好了(#load 相當於腳本的拚接)

測試程式碼片段:

無法直覺撰寫擴充方法類別,但好處是可以直接撰寫擴充方法?

正規的擴充方法類別寫法,在 csx 中有錯誤訊息 methods must be defined in a top level static class
從腳本的角度來看,寫的 Code 更少也算是好事

基於原理的關係,寫在 csx 中的類別會是巢狀類型,而擴充方法靜態類別必須是第一層,所以擴充方法的寫法要做點轉換。但這樣一來程式碼在 .csx 中,和在 .cs 中就需要做額外的調整了,無法做完整的驗證。

更詳細原理,可以參考 RoslynPad 的 issue: https://github.com/aelij/RoslynPad/issues/110

流通性:

RoslynPad 的格式是 .csx 檔,是很通行的格式,甚至 Azure 上也能用(連結),透過 csi.exe 或 dotnet install 指令安裝 dotnet-script 來執行。

LINQPad 的格式是 .linq 檔,不是通用格式,用 LINQPad.exe 或 lprun.exe 執行。

因為都需要額外安裝,個人使用來說是沒有太大差異。但到別人的機臺上執行的話,畢竟 .csx 是官方出的格式,或許說服起來比較有力吧。

當然 LINQPad 有在西澳註冊公司,是個老牌子的商業軟體,不是來路不明的東西,也有人比起開源第三方更信任付費工具。

連線切換:

其實這不是 RoslynPad 該做的事,或許可以透過一些設計,讓腳本讀取文件來達成切換。LINQPad 不改 Code 就能跑在不同的資料庫,確實是很方便的事。

資料庫存取:

有種下 SQL vs ORM 的感覺,RoslynPad 要取得資料庫資料,我目前最簡便的寫法要三行,

  1. 參考 Dapper NuGet
  2. using Dapper 命名空間
  3. new SqlConnection 然後下 SQL 作 Query

下 SQL 的時候可能要一邊看 Schema 找表名、欄位名等等,用 MSSQL 的話,這時候開個 SSMS 來組 SQL 可能比較順手。

相比之下 LINQPad 只要一行,而且有 IntelliSense,ORM 在建好模型的狀況下,各種串接就是特別順。

移至定義:

RoslynPad 沒有移至定義(Navigation),畢竟不是 IDE ,沒有是很合理的事,或許寫著寫著當開始變地越來越需要這個功能的時候,就是它該抽成專案或類別庫的時候了吧

Code Block 收合:

RoslynPad 目前沒有收合區塊的功能,但以後或許會有吧,畢竟很多編輯器都有,不是 IDE 獨有的。我若在 .csx 裡有寫方法或類別,捲軸拉來拉去時就會想念這個功能。

記住上次狀態:

好不好用見人見志,目前感覺好處是關得快,關的時候不用一一存檔。

多螢幕投影 IntelliSense Bug ( https://github.com/aelij/RoslynPad/issues/396): 

測試 15.1 版時,我用筆電接雙螢幕,程式在副螢幕的 IntelliSense 窗口發生位移,且游標 Focus 離開編輯窗導致無法持續寫 Code。猜測這一塊是 .NET Core Avalonia 的 bug,問題很可能在下一版就自己消失了。

自動選項跳出,但打不出字,這時點一下視窗主題可以繼續

參考相對路徑:

理想上如果要把腳本分享出去,若有參考 dll 最好使用相對路徑像是 #r ".\bin\MyLib.dll" ,在 15.1 版中進行相關測試時,dll 的相關 IntelliSense 都正常,但執行時回報找不到 dll,猜測有設計相對路徑的規格,但出了點小問題。

相對路徑這功能,在 dotnet-script(連結) 是可正常執行的,這規格我想算是有共識的。

產品定位

https://github.com/aelij/RoslynPad/issues/30 作者強調了 RoslynPad 的定位,本身目的是一個用來方便測試 .csx 腳本,所以它相比 IDE 功能陽春許多,像是沒有中斷點功能等。

不過還是可以察覺,作者個人很喜愛的東西過程中順手就加了,非常佛心。像是可先 new 物件再用代碼校正直接幫你把等號和左邊的變數完成,這可是超高級的功能啊,VS 沒有這個功能,而要付費的 ReSharper 和 Rider 就有。

也算是開源軟體中一點有趣的事吧。

感想

RoslynPad UI 簡潔到很多功能在 UI 上都找不到,有些功能只有快速鍵,我還都是看 GitHub 上的 Issues 從作者的隻字片語中挖到的。雖然這是開源的,理論上看 Code 也找得到(?),但還是希望以後能在 Wiki 補一下文件。

我覺得 RoslynPad 已經為 .csx 撰寫補上了 C# 最重要的一味 IntelliSense,再加上可查看物件的 Dump,剩下的很多都算是錦上添花了。在寫 .csx 時,感受到的是一目瞭然的簡潔,用了哪些 dll、nuget 都用非常簡短方式描述,簡單的 using namespace 後,馬上就進到的實作環節沒有一絲多餘。

.csx 如果是簡單的任務,只要一個文檔就能完成任務,檔案內有條理地起承轉合,可讀性高好維護。而 #load 則可以在 .csx 中載入其它 .csx,模組化帶來的靈活及複用則能應付更複雜的狀況,讓人期待它的可能性。

關於 .csx nuget 的引用語法,官方原生似乎沒有定義,格式各家略有不同,例如:

  1. #r "nuget: Dapper, 2.0.90"
  2. #r "nuget: Dapper/2.0.90"

,這導致不同工具開發的 .csx 也只有相應的工具可以運作。像 Dump 也是 RoslynPad 的特色,移植到 dotnet-script 就會導致錯誤。

更深入像是 #load 別的 .csx 時,是否一併載入檔案內參考的 NuGet 和 using 的空間名稱,我看回報 Issues 時的問答也不像是有標準作法在可自行定義的範圍,這種定義上不確定性對於想深入使用的人,真的會怕投入的時間打水漂。不過就目前來說不用深入就已經很夠用了,例如:我想分享一個真的可以動的 Dapper 使用範例,就只要分享一個文檔就夠了,效果還是蠻好的。

再看 LINQPad 對我來說也還是難以被取代,甚至相同功能卻更加順手(人家用這個吃飯的嘛),而且做為一個成熟的產品,你一定可以在導覽列找到所有功能和快速鍵(有些放在 Help>Shortcuts)。

LINQPad 的賣點是資料庫串接,取得 Table 資料只要寫一行 Code,驗證可行性做個 MVP 來說堪稱極速。

其次是 Dump 的極致優化,對 DataTable、IEnumerable 等型別特化的 Dump 樣式都讓資料一目瞭然,某方面來說其實是資訊省略,有 Debug 過 DataTable 的人應該都知道有多麻煩。而 RoslynPad 的作者對 Dump 也有自己的考量,所以呈現的是原本的物件,各有好壞,哪天想研究 DataTable 的細部結構用 RoslynPad 應該是不錯的選擇。

以個人快速開發原型來說,還是會傾向使用 LINQPad。但若以腳本釋出給別人的角度,則可能開始考慮 .csx 檔,搭配 RoslynPad 就會有很高的可維護性(IntelliSense)。畢竟 LINQPad 沒有付費的話,是不好維護的。

最後比較不相關的:後來想想 LINQPad 的 FREE 版更像是一種保障,保證寫好的腳本也可以順跑在任何沒有購買 LINQPad 的環境中。

參考資料

https://github.com/aelij/RoslynPad/issues/272 在一個相關的 issue 中,作者回答一個稍微偏題的發問,讓我挖到了好用的快捷鍵

https://docs.microsoft.com/zh-tw/archive/msdn-magazine/2016/january/essential-net-csharp-scripting 官網上 .csx 相關介紹