Portability Analyzerを使ってライブラリの.NET Standard準拠を調べよう
Visual Studio 2017のリリースを迎え(るにあたり)、(技術的には、直接的にそこに関連付いているわけではないけれど)「.NET Standard」というキーワードが強く聞こえてくるようになった気がしています。
そうそう、先日、 Xamarin Studio も .NET Standard Library 対応しましたね。
ということで、今回は既存資産のライブラリ実装が、.NET Standardに準拠しているかどうか調べることができる「Portability Analyzer」というものを使ってみたいと思います。
ちなみにGithubからソース取らなくても、以下のGUI操作だけで使えます。
※以下はVisual Studio 2015を使います。明日か明後日にVS2017版に差し替えるかも・・・
.NET Portability Analyzerをインストール
※2017.3.8追記
2017/3/8現在のVisual Studio 2017では「拡張機能と更新プログラム」からだと「.NET Portable Analyzer」が出てこないみたいです。
以下から.vsix ファイルをダウンロードしてダブルクリックでインストールするとVS2017でも使えるようになります。
でも、VS2017が不安定になる可能性があります、と警告文が出るので自己責任でご利用ください(正式対応じゃないってことですね)。私の環境では、特に何かが変になることなく動いていました。
.NET Portability Analyzer - Visual Studio Marketplace
Visual Studio 2015を起動。
メニュー「ツール → 拡張機能と更新プログラム」を選択。
「オンライン → .NET Portable Analyzer」を選択してインストール。
VSの再起動を促されます。
調査対象のライブラリプロジェクトを開く
調査対象のライブラリプロジェクトをVisual Studioで開きます。
今回は以下のような「OmnipotentLibrary」というライブラリプロジェクトを調査対象としました。
プロジェクトに含まれるMyLogger.csは以下のような、Reflectionを使ったキビシイ実装です。
// MyLogger.cs using System; using System.Security; using System.Reflection; using System.Diagnostics; namespace OmnipotentLibrary { public class MyLogger { /// <summary> /// メソッドの開始時に呼び出します。 /// </summary> /// <returns></returns> [DynamicSecurityMethod] public static DateTime Start() { DateTime now = DateTime.Now; const int callerFrameIndex = 1; StackFrame callerFrame = new StackFrame(callerFrameIndex); MethodBase callerMethod = callerFrame.GetMethod(); Debug.WriteLine(string.Format("start {0}()", callerMethod.Name)); return now; } /// <summary> /// メソッドの終了時に呼び出します。 /// </summary> /// <param name="start"></param> [DynamicSecurityMethod] public static void End(DateTime start) { DateTime now = DateTime.Now; TimeSpan ts = now - start; const int callerFrameIndex = 1; StackFrame callerFrame = new StackFrame(callerFrameIndex); MethodBase callerMethod = callerFrame.GetMethod(); Debug.WriteLine(string.Format("end {0}(): {1}ms", callerMethod.Name, ts.TotalMilliseconds)); } } } namespace System.Security { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] internal sealed class DynamicSecurityMethodAttribute : Attribute { } }
Portability Analyzerの設定を行う
ソリューションエクスプローラでプロジェクトを選択、マウス右ボタンクリック、メニュー「Prtable Analyzer Settings」を選択します。
表示された以下のウィンドウで「Target Platforms」を選択します。
「Target Platforms」とは、アナライズ対象のプラットフォームです。調査対象のプロジェクト(OmnipotentLibrary)が、「対象のプラットフォームに準拠しているか?」調べる対象になります。
ここでは、.NET Core 1.0 / 1.1 / 2.0、.NET Framework 4.5 / 4.5.1 / 4.5.2 / 4.6 / 4.6.1 / 4.6.2、.NET Standard 1.0 / 1.1 / 1.2 / 1.3 / 1.4 / 1.5 / 1.6 / 2.0、Xamarin Android 1.0.0、Xamarin.iOS 1.0.0.0に準拠しているか?を、アナライズする設定としました。
Portability Analyzerを実行する
ソリューションエクスプローラでプロジェクトを選択、マウス右ボタンクリック、メニュー「Analyzer Azzembly Portability」を選択します。
アナライズが完了すると、「Portability Analyze Results」ウィンドウに結果が表示されます。
「Open Report」をクリックすると結果のExcelファイルが起動されます。
結果を分析する
アナライズ結果のExcelは、2シート構成です。
1シート目は結果のサマリーになっています。
横長なので折り返し加工していますが、以下のような感じです。
表のヘッダ(青い部分)が「ターゲットプラットフォーム」、その下の数値が「分析結果のスコア」です。
スコア100(緑)が準拠OK、スコア100未満(オレンジ)が準拠NG、となります。
このライブラリはReflection系を使用しているので、.NET Core 1.0 / 1.1 や .NET Standard 1.xなどでは結果NGとなりました。
2つ目のシートには、スコアが100未満であった原因の詳細がリストされています。
T:System.Diagnostics.StackFrame とか T:System.Runtime.InteropServices.GuidAttributeを使ってるのが悪いよー、Supported: 2.0+じゃないと使えないよー、っていう結果が分かります。
まとめ
ということで
Let’s head to .NET Standard!