ねののお庭。

かりかりもふもふ。

.NET Standardの実体について。

.NET Standard完全に理解していますか?

.NET Standard,いろんな環境で使える共通のAPIという認識はみなさんしていると思います。が、内実...というか.NET Standardで作成したライブラリが、どのように.NET Core環境と.NET Framework環境で動いているのか、とか、.NET Standard対応のnuget packageあるけどこれ標準ライブラリに含まれているぞ...?ぶつからないのか...?とか、まぁ気になるところはいろいろあります。自分もいろいろ混乱していたので、調べたこととかまとめることとします。

そもそも.NET Frameworkと.NET Coreの標準ライブラリの違い。

実行環境としては.NET Frameworkと.NET Coreを考えます。Unityも2018.1からは.NET Standard2.0に対応していますが、今回はスルー。

.NET Frameworkでは標準ライブラリの多くはSystemとmscorlibなどのアセンブリに雑に放り込んであります。なので大きめなアセンブリがどーんとそこまで分割されずに追加されているような感じですね。

それに対して.NET Coreは標準ライブラリも、全て細かく個々のパッケージとして管理されるようになりました。nuget.orgとか除くとSystem.xxxみたいな標準で使える奴らがいますよ。

なのでターゲットフレームワークが.NET Standardのプロジェクトで、.NET Standardには定義されてないけど、.NET Coreには標準で入っていて、NET Standardに実は対応しているパッケージ、みたいなパッケージを.NET Standardのプロジェクトで参照することで、本来.NET Standardでは定義されていないクラスなども使えて、いろいろ幅が増えたりします。何言ってるかわからなそう。

たとえば、.NET Standard2.0にはSystem.Numerics.Vector2というクラスは定義されていません。が、.NET Coreでは標準で使えます。 でも.NET Standardなライブラリを作成しているとき、使いたいとします。 そいういう時は、適したnuget packageを.NET Standardなライブラリを作成しているプロジェクトで参照してあげると、使えるようになってハッピー、というの具合です。 (.NET Standard2.1からはSystem.Numerics.Vectorsが仲間入りするらしくて私はハッピー)(3x3行列がほしいけど)

.NET Standard1.xと2.xの大きな違い

まぁ定義されているAPIが沢山増えましたよ...というだけでなく。

.NET Standardを使うためにはNETStandard.Libraryというものがひっついて回ります。ソリューションエクスプローラーで依存みてみるとわかります。(.csprojには現れません。) まぁNETStandard.Libraryとかいう名前なのでなんとなくは想像は付きますね。なにに依存しているかみてみましょう。

1.6はまだまだ下があります。大量に依存しているパッケージがあることが伺えます。 それに対して2.0はただ一つだけ。 これは一体どういうことでしょうか。結論からいうと、1.0ではNETStandard.Libraryではただのメタパッケージでした。 メタパッケージとはその他の依存しているライブラリとかのリストです。なので、NETStandard.Libraryが設定されていれば、その他の.net standardで定義されているライブラリがガッと追加される感じでした。しかし.NET standard2.0からはそういうそういった感じではなくなり、暗黙的にパッケージは参照されるようになりました。 そのため、大量のパッケージの依存はなくなりました。が、その代わり(?)netstandard.dllというものが追加されました。

netstandard.dll

NETStandard.Libraryは実態としていったいどうなったかというと、netstandard.dllという形をとりました。これはなかなかおもしろくて、実態は.NET Framworkの場合はSystemやmscorlib,.NET Coreの場合は各パッケージのアセンブリを参照するようなTypeForwardedToがひたすら書かれているdllになります。dnSpyとかを使ってnetstandard.dllを開いてみると、下のようになっていてます。

大量のTypeForwardedToがあります。ようするにnetstandard.dllには実装の実態はなくて、.NET Coreであれば各パッケージのアセンブリ.NET FrameworkであればSystemとか、mscorlibとかに飛ばされるようになっています。.NET Core,.NET Framworkのそれぞれで提供されるnetstandard.dllの中身をもうちょっと見ていきます。次はILDASMを使って中身を見ていきます。

.NET Frameworkの方はこう。

.NET Coreの方はこう。

.NET Frameworkではmscorlibに、.NET Coreでは各パッケージに参照が飛ばされていることが分かります。

こうして、.NET Standardで作成されたライブラリが、あらゆる環境で動作するようになるんだなぁということが分かります。

まとめ

.NET Standardでは、

  • 1.xではメタパッケージであったが2.xからは暗黙的に標準ライブラリは参照されるようになった。
  • .NET Standardなライブラリでは、netstandard.dllを介して、実際の実装があるところに飛ばして、いろいろな環境で動くようになっている。

(おまけ)coreclrとcorefx

いろいろ見ていきましたが、ふと疑問に思うところがありました。 coreclrとcorefxです。.NET CoreはOSSとして公開されています。なので標準ライブラリがどういう実装なのかなーと気になり眺めることがありました。coreclrは.NET Coreのランタイム、corefxでは標準ライブラリ、という感じなのですが、ふと思いました。

Objectとかintみたいなランタイムとべったりしていそうなやつらどうなっているの...?

と。これcorefx側で定義するわけにもいかんやろ、とか思った次第で。でなんぞと思ったらclrのreadmeにちゃんといろいろ書いてあって、

clrでは本当に必要最低限のクラス定義とかはしていて、でもそれらのクラスは完全にprivateになっているらしい。System.Private.CoreLib.dllの中にObjectとかstringは詰め込まれている。 でも、ここに外からは直接はアクセスさせないで、corefx側が一度すべてそれらの型をSystem.Runtime.dllとかの公開されているdllで受け止めてから、System.Private.CoreLib.dllに最終的に飛ばす、みたいな実装がされているらしい。

まめ知識

.NET CoreはOSSです。が、デバッガはどうやらOSSではなく、Visual Studioとかの製品群の一部らしい。一応VSCodeでもデバッグできるやんと思ったのですが、どうもあれもVSCodeOSSでもVSCodeのバイナリにMSの署名されていないものでは動かないとかの制限はあるらしい。

参考