vscodeのC#補完で、zip展開したSDKを使用させる

# 始めに

C#で、現在絶賛開発中の機能を使用したいことがたまにある。
大抵の機能は[dotnetのmygetリポジトリ](https://dotnet.myget.org/gallery)を使用すれば取得可能なので問題ないが、ランタイムまで含む変更の場合、利用できない機能もある。(netcoreapp2.1対応とか)

これら機能を試すのに、Visual Studioのプレビュー版はちょっと重いので、Visual Studio Codeを使いたいと思ったが、
思ったより手間取ったので備忘録として書く。

なお、記事執筆時点では、最新のプレビューは2.1.300-preview1-*で、安定板は2.1.4なので、それを前提として書いている。

# プレビュー版SDKの使用

このような開発中の機能に関しては、ソースからコンパイルするのが細かい挙動も把握できて一番良いと思うが、いかんせん準備等が面倒で、難易度も高い。少なくとも自分はしたことはない。

そこで、もう一つの選択肢となるのが[dotnet-cliのサイト](https://github.com/dotnet/cli)から、開発版SDKを取得してくる方法である。

配布されているSDKは、MSIとzip圧縮されたものがある。それぞれの特徴に関しては、

* パッケージ(MSI,rpm,deb等)
    * マシンにインストールして使用する
        * システム全体に影響がある
    * 実行ファイルへのパスも通してくれる
* zip
    * zip展開して使用する
        * ユーザーローカルへの影響のみ
    * パス等は通してくれない

当然常用するならMSIなのだが、うかつにプレビュー版のSDKを入れると、既存のVisual Studio等の挙動に影響を与える場合があるので注意が必要。そしてプレビュー版だけに、もしかすると後戻りがかなり面倒な破壊的変更が加えられる可能性もある。
そこで、zipデプロイを使用すれば、実行パスの入力等、多少面倒な所はあるものの、あるプロジェクト限定でプレビュー版を使用することが可能となる。

しかし、実際にプレビュー版SDKであれこれしようとすると、素の状態のエディタでは書くのが辛くなってくる。
特にクラス定義部分等は、ウェブ上にもリファレンスが載ってない場合が多いので、参照用ソース(corefxソース等)を行ったり来たりすることになるが、正直これはかなり苦痛。

そこで、何らかの入力支援があるエディタ、あるいはIDEを使用したいということになるが、自分の場合は[Visual Studio Code(vscode)](https://code.visualstudio.com/)を使用することが多い。

# vscodeのC#拡張(omnisharp-vscode)を使う場合の問題点と解決方法

ただ、このvscodeのC#拡張、デフォルトでシステムのdotnetを使用するようにできており、netcoreapp2.1を指定しても当然エラーを出す。

そこで、omnisharpにプレビュー版SDKを使うように指示する必要がある。omnisharp自身の設定は以下のページで書いてあるように、複数の方法が用意されている。
https://github.com/OmniSharp/omnisharp-roslyn/wiki/Configuration-Options
今回は、設定ファイルであるomnisharp.jsonに記述する方法を書く。

## omnisharp.jsonの設置

さてこのomnisharp.json、仕様では以下の位置にあるファイルを読み込むようになっている。

* ユーザーホームディレクトリの.omnisharp/omnisharp.json
* プロジェクトファイル、あるいはソリューションファイルにあるomnisharp.json

基本的にはプロジェクトファイルにある方が優先度は高い。

## 設定項目

さて、実際何を書くか、という点だが、自分が探した範囲ではマニュアル的なものは無かった。そこで、ソースを見てみると、以下のようなものが見つかる。
https://github.com/OmniSharp/omnisharp-roslyn/blob/master/src/OmniSharp.MSBuild/Options/MSBuildOptions.cs

この内、筆者は以下のような項目の設定をした。

### MSBuildSDKsPath

MSBuildの15から追加されたもので、`<Project>`要素に`Sdk`属性を加えると、
暗黙的にインポートしてくれるという機能が存在する。

この設定は、そのインポート元のファイルが存在するパスを指定する設定となる。
大体の場合は、`[SDK展開先]/sdk/[SDKバージョン]/Sdks`を設定すればOK

### ToolsVersion

恐らくMSBuildのバージョンが関係している。恐らくMSbuild内で`$(MSBuildExtensionsPath)/$(ToolsVersion)`というパスの組み立てを行うので、SDKフォルダの下にあるバージョンを入れれば間違いはないと思われる。
dotnet-sdk-2.0時点ではここは`15.0`となる。

### MSBuildExtensionsPath

https://docs.microsoft.com/ja-jp/visualstudio/msbuild/msbuild-reserved-and-well-known-properties の`MSBuildExtensionsPath`と恐らく同じ

大体の場合は、`[SDK展開先]/sdk/[SDKバージョン]`を指定しておけばOK

### RoslynTargetsPath

C#やF#のためのプロパティの設定ファイルがある場所。

大体の場合は、`[SDK展開先]/sdk/[SDKバージョン]/Roslyn`を指定しておけばOK

### CscToolsPath

csc.exeまたはcsc.dllがあるディレクトリのパス。SDKの中にあるcsc.dllを使用しても問題ないが、別途cscを用意する場合、nuget.exeで`Microsoft.Net.Compilers`を取得して、その`tools`フォルダを指定すること。
SDK付属のcscを使用する場合は、指定は`[SDKパス]/Roslyn/bincore`となる

nugetからインストールする場合は、`Microsoft.Net.Compilers`を`nuget.exe install`で取得し、配下に`csc.exe`があるはず。
csprojファイルのPackageReferenceに追加でOKかもしれないが、自分が指定したときはうまくいかなかったので、うまくいかなかったらnugetで展開しておくこと。
プレビュー版のコンパイラが必要な場合、[roslynのmygetリポジトリ](https://dotnet.myget.org/gallery/roslyn)から持ってくること。

cscを確保したら、cscがあるフォルダのパスを指定しておく。


## omnisharp.jsonの例

筆者は`G:/bin/dotnet-sdk-latest-win-x64`にzipを、`G:/bin/csc/`以下にcscを展開したので、以下のような設定になった。

```json
{
  "msbuild":{
    "MSBuildSDKsPath":"G:/bin/dotnet-sdk-latest-win-x64/sdk/2.1.300-preview2-008235/Sdks",
    "ToolsVersion":"15.0",
    "MSBuildExtensionsPath": "G:/bin/dotnet-sdk-latest-win-x64/sdk/2.1.300-preview2-008235",
    "RoslynTargetsPath": "G:/bin/dotnet-sdk-latest-win-x64/sdk/2.1.300-preview2-008235/Roslyn",
    "CscToolPath": "G:/bin/csc/Microsoft.Net.Compilers.2.6.1/tools"
  }
}
```

上のファイルをcsprojの隣に置いて、vscodeを再起動した所、該当csproj限定で補完等が効くようになった。

## 設定変更後の注意点

omnisharp-vscodeによりRestoreが促されるが、omnisharp-vscodeは標準パスの`dotnet`コマンドを使おうとするので、ここでリストアしようとしても失敗するだけなので、拡張からRestoreするように通知が来たら無視すること。
もしプロジェクトのRestoreが必要な場合、コマンドラインから直接Restoreした後、vscodeを再起動すればOK。再起動後に補完も追従する。

また、**デバッグ実行まではやってないので、誰か知っている人いたら情報求む。**

# 終りに

omnisharpのドキュメントは一応あるものの、量としては少ないので、結構ソースを読む必要がある箇所が多いのは若干痛い。
大体はソース内を`Options`で検索すれば出てくるが、やはり公式のドキュメントが欲しいところ。
omnisharpのソースは https://github.com/OmniSharp/omnisharp-roslyn にある。

開発中の機能を使うので、恐らく不可解な動作も数多くでると思われるが、一番大事なのは**転んでも泣かない**精神である。後何か不具合かな?という挙動があったら本家にフィードバックしよう。