dotnet-exec 小工具
dotnet-exec?小工具
Intro
在之前的文章中很多會(huì)有一些示例代碼,這些代碼一般都是一些很小的示例,尤其是介紹一些新特性的示例,基本上不會(huì)引用其他包,只有 SDK 就可以執(zhí)行,對(duì)于這些示例,一般會(huì)每個(gè)實(shí)例單獨(dú)一個(gè)文件,示例程序的入口文件是 MainTest 方法,都用 Main 會(huì)造成沖突,所以用了另外一個(gè)名字,而 Program 的 Main 方法里或者頂級(jí)程序語(yǔ)句中調(diào)用對(duì)應(yīng)示例的 MainTest,這樣的話每當(dāng)我想只執(zhí)行每一個(gè)示例的時(shí)候我就需要修改 Program 中的方法調(diào)用

于是就想著寫(xiě)一個(gè)小工具,用來(lái)直接調(diào)用對(duì)應(yīng)的示例,這樣既不破壞原來(lái) dotnet run 執(zhí)行運(yùn)行的效果,又可以直接執(zhí)行某一個(gè)示例,今天開(kāi)源的這個(gè)小工具 dotnet-exec 就是解決這個(gè)小問(wèn)題的,下面來(lái)看一下如何使用以及如何實(shí)現(xiàn)的吧
GetStarted
首先需要安裝 dotnet tool,dotnet tool 基于 .NET 6/7,需要安裝 .NET 6 或者 .NET 7 SDK,SDK 安裝之后
執(zhí)行下面的命令即可安裝
dotnet?tool?install?-g?dotnet-execute
對(duì)應(yīng)的命令是 dotnet-exec,可以使用 dotnet-exec -h 來(lái)看支持的選項(xiàng)

目前主要用到的 Options:
--entry指定程序的入口,默認(rèn)值是按我自己的習(xí)慣用的MainTest,可以根據(jù)需要自定義,如果有Main方法會(huì)優(yōu)先使用Main方法--lang-version指定 C# 語(yǔ)言版本,默認(rèn)使用Default等同于Latest,如果需要使用預(yù)覽版特性需要指定為Preview--args/--arguments指定用戶需要傳入的參數(shù),等同于Main方法的args參數(shù)-c/--configuration指定編譯的優(yōu)化級(jí)別,默認(rèn)是 Debug,不進(jìn)行優(yōu)化,可以指定為Release
Sample
百聞不如一見(jiàn),來(lái)看幾個(gè)使用的示例吧:
這里是 C# 10 中的一個(gè)常量插值字符串的示例,從下圖中可以看到代碼里沒(méi)有定義 Main 方法,定義了一個(gè) MainTest 的靜態(tài)方法,我們執(zhí)行 dotnet-exec .\ConstantInterpolatedStringSample.cs 可以看到,執(zhí)行了 MainTest 方法中的邏輯并且,輸出了期望的結(jié)果

這里是前段時(shí)間寫(xiě)的一個(gè) C# 11 的一個(gè)新特性—— RawStringLiteral

我們可以通過(guò) dotnet-exec .\RawStringLiteral.cs --lang-version Preview 來(lái)執(zhí)行這個(gè)示例,這里我們指定了 --lang-version 為 Preview 以啟用還在 Preview 的語(yǔ)言特性

針對(duì)原有的 Main 方法和頂級(jí)程序語(yǔ)句也是支持的,我們來(lái)看幾個(gè)示例


Implement
它的實(shí)現(xiàn)原理其實(shí)比較簡(jiǎn)單,利用 Roslyn 去編譯這個(gè)文件,增加了 Global using 的支持,并且會(huì)加上默認(rèn)的 Global using,這樣代碼里可以簡(jiǎn)單一些,現(xiàn)在寫(xiě)的很多示例會(huì)啟用隱式命名空間引用,這樣會(huì)方便很多
首先會(huì)嘗試編譯為一個(gè) Console 應(yīng)用,頂級(jí)語(yǔ)句這種語(yǔ)法只支持 Console 應(yīng)用,這樣如果是頂級(jí)語(yǔ)句或者包含 Main 方法就和 dotnet run 的運(yùn)行效果是一樣的,如果沒(méi)有 Main 方法,編譯會(huì)報(bào)一個(gè)找不到 Main 方法的錯(cuò)誤,然后會(huì)嘗試編譯為一個(gè) dll 通過(guò)反射的方式調(diào)用自定義的入口,更多細(xì)節(jié)可以參考源碼:https://github.com/WeihanLi/dotnet-exec/blob/1c83e366c81ab7a51e0995ed0f2a07845b668b89/src/dotnet-exec/CodeCompiler.cs#L38
More
目前只是做了比較簡(jiǎn)單處理,只編譯了單個(gè)文件,而且沒(méi)有檢測(cè)項(xiàng)目中的包引用,如果有引用別的項(xiàng)目和文件,現(xiàn)在是不能處理的,后面可以解析文件所在的項(xiàng)目文件中的包引用依賴(lài),編譯整個(gè)項(xiàng)目,但是這樣相對(duì)來(lái)說(shuō)會(huì)復(fù)雜一些,實(shí)現(xiàn)起來(lái)可能不會(huì)走現(xiàn)在的方式了,后面有需求的話再說(shuō)吧,暫時(shí)基本可以滿足需要
如果你也有類(lèi)似的需求,可以試一下看能否滿足你的需要
References
https://github.com/WeihanLi/dotnet-exec https://www.nuget.org/packages/dotnet-execute/
