C#のテストコードをサクッと試す時はdotnet-scriptとVSCodeの環境を整えておくと便利

C#で開発時、ちょっとしたテストコードをスクリプト言語のようにコンパイルを挟まず実行できる環境を用意しておくと良いと考えています。C#はコンパイルして実行するまでに、そこそこ手間がかかりますし。

ググるとC#インタラクティブ[^1]、csi[^2]という手段も出てきます。
ただし今回は以下の条件から、**dotnet-script**に採用します。
https://github.com/filipw/dotnet-script

- 開発環境はmacOS
- IDEに依存しない

[^1]: C#インタラクティブはVisualStudio依存
[^2]: csiはMac向けにリリースされていないため、本記事では扱わない(参考:https://www.buildinsider.net/language/csharpscript/01)





## .NET Core 2.1SDKのインストール

[本家のマニュアル](https://github.com/filipw/dotnet-script)に従ってdotnet-scriptの環境を構築していきますが、実行させるにあたって**.NET Core 2.1SDK**は必須です。以下のサイトからダウンロードしてインストールしておきます。
https://dotnet.microsoft.com/download/dotnet-core
※C#8.0を使用する場合は.NET Core 3.1SDKをインストールします。ちなみに.NET Core3.1SDKだけではdotnet-scriptは動きません。

## dotnet-scriptのインストール

### dotnet toolでインストール

プラットフォーム問わず、以下のコマンドでdotnet-scriptをインストールできます。

```shell
$ dotnet tool install -g dotnet-script
```

### curlでインストール

macOSの場合は以下のcurlコマンドでもインストールできます。

```shell
$ curl -s https://raw.githubusercontent.com/filipw/dotnet-script/master/install/install.sh | bash
# もしパーミッション周りでエラーを吐く場合は以下のコマンドを実行してください
$ curl -s https://raw.githubusercontent.com/filipw/dotnet-script/master/install/install.sh | sudo bash
```


## (補足)エディタはVSCodeを使用

使用するエディタは何でも良いですが、僕はサクッと環境を構築できるVisualStudioCode(以下:VSCode)を使いました。

- MicrosoftのC#
- LeopotamのC# FixFormat

この2つをExtensionsをインストールしておきます。
コード補完が利くようになり`Shift + Option + F`でソース整形されるようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/ce7a2bb8-0b7d-6e56-e1d3-0a4cd0d17b33.png" width=500 />


これで環境構築は完了です。

## Hello world!する

```shell
$ dotnet script init
```

initコマンドを実行すると、以下のテンプレートファイルが生成されます。[^3]

```
├── main.csx
└── omnisharp.json
```
[^3]: 既にcsxファイルが存在する場合は生成されません

以下のコマンドを実行すると`Hello world!`と出力されます。

```shell
$ dotnet script main.csx
```




## パスの扱い

指定したパスの扱いについて調査していきます。
以下のファイル構成をサンプルに調査を進めます。

```
├── Sample1.csx(dotnet-script実行ファイル)
├── test01.txt
└── test02.txt
```

試しに以下のソースコードを実行してみます。

```cs
var files = Directory.GetFiles(".");
foreach(var filePath in files)
{
    Console.WriteLine(filePath);    
}
```

以下のログ出力の通り、**実行ファイル(Sample.csx)を起点にした相対パス**のようです。

```
./test01.txt
./test02.txt
./Sample1.csx
```

## コマンドライン引数の取得方法

```
$ dotnet-script Sample1.csx arg1 arg2 arg3
```

上記のようにコマンドライン引数にarg1, arg2, arg3と3つの値をセットしてスクリプト側で受け取る方法です。


```cs
Console.WriteLine(Args[0]);
Console.WriteLine(Args[1]);
Console.WriteLine(Args[2]);
```

このように`Args`に詰め込まれているので、上記のようなコードで受け取ることが出来ます。
ちなみにArgsは `IList<string>`ですので、要素数を取得したい場合は、`Length`ではなく`Count`を使用します。


コマンドライン引数が必須のスクリプトの場合、以下のように**Argsがnullになる**場合があり、以下のようなエラーが出力されます。

```
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
```

このようなnullチェックを事前に走らせた方が良いでしょう。

```cs
if (Args == null && Args.Count <= 0){
   // コマンドライン引数はありません
   return;
}
```

## ファイルのリネーム処理サンプル

サンプルを１つ作ってみます。

以下は指定ディレクトリ内の、`.txtファイル`を`.csファイル`にファイルリネームするというものです。

```RenameTxt2Cs.csxの一部
var dirPath = Args[0];
var files = Directory.GetFiles(dirPath, "*.txt");
foreach(var filePath in files)
{
    var dirPath = Path.GetDirectoryName(filePath);
    var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
    var newPath = $"{dirPath}/{fileNameWithoutExtension}.cs";
    File.Move(filePath, newPath);
}
```
全ソースは[コチラ](https://gist.github.com/baobao/8a12c1156263ff25232c0b3c4f3dd540)

以下のように引数にディレクトリパスを指定してdotnet-scriptを実行します。

```
$ dotnet-script RenameTxt2Cs.csx 任意のフォルダパス(絶対パス or 相対パス)
```


## 最後に

dotnet-scriptを使うとC#をインタプリタ型言語のようにライトにC#を実行できるようになります。
本記事では触れていませんが**REPL**でも動作します。
**テストコードを書いてサクッと挙動をチェックする時などに使えます**のでC#を扱うエンジニアはdotnet-scriptが動く環境を作っておくと開発効率が上る可能性はあるなと思いました。


## トラブルシューティング

### .NET Core2.1が未インストールエラー

dotnet-scriptコマンド実行時に以下のエラーが出た場合は**.NET Core2.1が未インストール**です。
インストールすると解決します。
バイナリは[コチラ](https://dotnet.microsoft.com/download/dotnet-core)からダウンロードできます。

```
It was not possible to find any compatible framework version
The framework 'Microsoft.NETCore.App', version '2.1.0' was not found.
  - The following frameworks were found:
      3.1.6 at [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

You can resolve the problem by installing the specified framework and/or SDK.

The specified framework can be found at:
  - https://aka.ms/dotnet-core-applaunch?framework=Microsoft.NETCore.App&framework_version=2.1.0&arch=x64&rid=osx.10.15-x64
```

### `dotnet script`と`dotnet-script`コマンド

dotnet toolでインストールした場合は`dotnet script`、curlでインストールした場合は`dotnet-script`を使用します。少しハマりました。

## 環境

- dotnet-script v0.53.0
- macOS 10.15.5