この記事は、「C# Advent Calendar 2020」 9日目の記事、かつ 「PowerShell Advent Calendar 2020」 9日目の記事だ。
スミマセン。横着した。
この時期になれば .NET Interactive の Preview 4 が出てるだろうしその記事でも書こうかな~ などと目論んでいたものの、 残念ながら登場しなかった。
このため、 .NET Interactive .NET 5 対応版の導入と、 Variable sharing の内容でお茶を濁そうと思う。
.NET Interactive のなんたるかについては、以前の以下の記事で取り扱っているので、そちらを参照願いたい。
.NET Interactive を .NET 5 で動かしてみる
いきなり本題とは関係ない話になるが、 せっかく .NET 5 がリリースされたところなので、 .NET Interactive を .NET 5 で動かしてみよう。
12/8 現在、NuGet で公式にリリースされている .NET Interactive は、 9月にリリースされた Preview 3 に少し更新が加えられた、 1.0.155302 だ。
これは、 .NET Core 3.1 上に構築されている。
一方で 11/27 頃のビルド (dotnet/interactive@61d2315) あたりでは、既に .NET 5 対応が済まされている。
更に、 何故か Visual Studio Code の .NET Interactive Notebooks 拡張では、 .NET 5 に対応した 1.0.160204 がリリースされている。
このため、 現時点で .NET Interactive で .NET 5 を扱う主な方法は、以下の通り。
- main ブランチの binder コンテナにアクセス
- Azure DevOps の CI ビルドの NuGet feed (dotnet-tools) から、 Glogal Tool を DL
- 実行例:
dotnet tool install -g Microsoft.dotnet-interactive --version 1.0.160204 --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
- 実行例:
- VS Code Insider を起動し、 .NET Interactive Notebooks 拡張の Preview をインストール
残念ながら、 .NET Interactive インストール済み Jupyter の docker イメージのようなものは 公式では用意されておらず、 コンテナを使いたかったら自分でビルドするしかない。
(そのせいで、 上記 binder の起動は遅い)
vscode 拡張だと、 コード補完が ignore case で効くのでとても書きやすい。
以下、 vscode の .NET Interactive Notebooks 拡張の バージョン 1.0.160204 での実行を前提とするが、 他の環境でも同様に動作するはずだ。
なお、 起動した Notebook やコンソールの .NET CLR のバージョンを知りたければ、 System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription
を実行すれば良い。
.NET 5.x.x と表示されれば、 .NET 5 で起動していることが確認できる。
Variable sharing とは
さて、ようやく本題。
.NET Interactive が面白いのは、 ひとつの Notebook 内で、 C#, PowerShell, F# の言語間の変数を共有できる点だ。
悪いなあ、 VB.NET。 このツールは3人用なんだ。
この変数を共有できる機能を、 variable sharing という。
使い方はとても簡単で、 #!share --from
マジックコマンドで、 参照する .NET カーネルと変数名を指定するだけだ。
但し、 読み込まれている型の空間は共有されない点には注意だ。
例えば、 C# で定義したクラスのインスタンスを PowerShell で読み込もうとしたり、
PowerShell でロードされているモジュールで定義された型のインスタンスを C# で読もうとすると、エラーになってしまう。
詳しくは、 interactive/variable-sharing.md · dotnet/interactive のドキュメントを参照。
但し、 PowerShell でよく使われる PSCustomObject
型については特別対応が入っているらしく、いい感じに Dictionary<string, object>
に変換されて C# でも扱える。
なにそれ。 PowerShell 内部でも欲しい機能なんだけど。
Variable sharing の使いどころ
例えば…
例えば……
………
うーん、よい例が思いつかない…
そもそも、 C# でできることはだいたい PowerShell でできるし、 その逆もまた然りなんだよな。
加えて PowerShell では、 Add-Type
で手軽に C# のコードを埋め込めるし…
強いて挙げるなら、 PowerShell は、付属のコマンドレットや追加モジュールによって、 I/O 操作やリソースの読み込みにが強い一方で、 パイプを交えたデータの処理はだいぶ遅いところだろうか。
例えば、 PowerShell で ファイルの読み込みなどを行いつつ、 大量のデータの処理は C# で行うといったような使い方はアリかもしれない。
#!pwsh
$data1 = Get-ChildItem *.json -Recurse | Get-Content -Raw | ConvertFrom-Json;
$data2 = Get-Clipboard;
#!csharp
#!share --from pwsh data1, data2
data1.Where(kv => kv.Key == "tools")
#!csharp
data2.First()
この程度のデータ処理なら PowerShell で全く問題ないレベルだが、 処理するデータの数が増えてくれば C# で実行するメリットが出てくるだろう。