dotnet-exec小工具

Intro

在之前的文章中很多会有一些示例代码,这些代码一般都是一些很小的示例,尤其是介绍一些新特性的示例,基本上不会引用其他包,只有 SDK 就可以执行,对于这些示例,一般会每个实例单独一个文件,示例程序的入口文件是 MainTest 方法,都用 Main 会造成冲突,所以用了另外一个名字,而 Program 的 Main 方法里或者顶级程序语句中调用对应示例的 MainTest,这样的话每当我想只执行每一个示例的时候我就需要修改 Program 中的方法调用.

dotnet-exec小工具

于是就想着写一个小工具,用来直接调用对应的示例,这样既不破坏原来 dotnet run 执行运行的效果,又可以直接执行某一个示例,今天开源的这个小工具 dotnet-exec 就是解决这个小问题的,下面来看一下如何使用以及如何实现的吧

GetStarted

首先需要安装 dotnet tool,dotnet tool 基于 .NET 6/7,需要安装 .NET 6 或者 .NET 7 SDK,SDK 安装之后

执行下面的命令即可安装

dotnet tool install -g dotnet-execute

对应的命令是 dotnet-exec,可以使用 dotnet-exec -h 来看支持的选项

dotnet-exec小工具

目前主要用到的 Options:

  • --entry 指定程序的入口,默认值是按我自己的习惯用的 MainTest,可以根据需要自定义,如果有 Main 方法会优先使用 Main 方法
  • --lang-version 指定 C# 语言版本,默认使用 Default 等同于 Latest,如果需要使用预览版特性需要指定为 Preview
  • --args/--arguments 指定用户需要传入的参数,等同于 Main 方法的 args 参数
  • -c/--configuration 指定编译的优化级别,默认是 Debug,不进行优化,可以指定为 Release

Sample

百闻不如一见,来看几个使用的示例吧:

这里是 C# 10 中的一个常量插值字符串的示例,从下图中可以看到代码里没有定义 Main 方法,定义了一个 MainTest 的静态方法,我们执行 dotnet-exec .\ConstantInterpolatedStringSample.cs 可以看到,执行了 MainTest 方法中的逻辑并且,输出了期望的结果

dotnet-exec小工具

这里是前段时间写的一个 C# 11 的一个新特性—— RawStringLiteral

dotnet-exec小工具

我们可以通过 dotnet-exec .\RawStringLiteral.cs --lang-version Preview 来执行这个示例,这里我们指定了 --lang-version 为 Preview 以启用还在 Preview 的语言特性

dotnet-exec小工具

针对原有的 Main 方法和顶级程序语句也是支持的,我们来看几个示例

dotnet-exec小工具

dotnet-exec小工具

Implement

它的实现原理其实比较简单,利用 Roslyn 去编译这个文件,增加了 Global using 的支持,并且会加上默认的 Global using,这样代码里可以简单一些,现在写的很多示例会启用隐式命名空间引用,这样会方便很多

首先会尝试编译为一个 Console 应用,顶级语句这种语法只支持 Console 应用,这样如果是顶级语句或者包含 Main 方法就和 dotnet run 的运行效果是一样的,如果没有 Main 方法,编译会报一个找不到 Main 方法的错误,然后会尝试编译为一个 dll 通过反射的方式调用自定义的入口,更多细节可以参考源码:https://github.com/WeihanLi/dotnet-exec/blob/1c83e366c81ab7a51e0995ed0f2a07845b668b89/src/dotnet-exec/CodeCompiler.cs#L38

More

目前只是做了比较简单处理,只编译了单个文件,而且没有检测项目中的包引用,如果有引用别的项目和文件,现在是不能处理的,后面可以解析文件所在的项目文件中的包引用依赖,编译整个项目,但是这样相对来说会复杂一些,实现起来可能不会走现在的方式了,后面有需求的话再说吧,暂时基本可以满足需要

如果你也有类似的需求,可以试一下看能否满足你的需要