Dot netconf2017 - VS拡張

77
Dawn Huczek Quick shot 作成時に学んだ VS拡張、RoslynDotnet.exe関連の知識

Transcript of Dot netconf2017 - VS拡張

Page 1: Dot netconf2017 - VS拡張

Dawn Huczek

Quick shot 作成時に学んだVS拡張、Roslyn、Dotnet.exe関連の知識

Page 2: Dot netconf2017 - VS拡張

自己紹介

・石川達也

・(株)Codeer 代表取締役

・Microsoft MVP

・ささいなことですが(ブログ)

・OSS

FriendlySelenium拡張

LambdicSql

Visual Studio and Development Technologies

http://ishikawa-tatsuya.hatenablog.com/

https://www.nuget.org/profiles/ishikawa-tatsuya

趣味はギターとライブラリ作成

Page 3: Dot netconf2017 - VS拡張

Codeer Ltd.

こんなメンバーでやってます!

ソフトウェア開発でお悩みの方は、いつでもご相談ください

Page 4: Dot netconf2017 - VS拡張

Quick shot

関数単体で実行するVS拡張(無料)

Page 5: Dot netconf2017 - VS拡張

Quick shot デモ

https://marketplace.visualstudio.com/items?itemName=ishikawa-tatsuya.Quickshot

Page 6: Dot netconf2017 - VS拡張

λ sql

仲間募集中!

Page 7: Dot netconf2017 - VS拡張

LambdicSqlデモ

https://github.com/Codeer-Software/LambdicSql

Page 8: Dot netconf2017 - VS拡張

SQL Server LambdicSql.SqlServer

My Sql

SQLite

Oracle

DB2

PostgreSql

95%

実装状況

共通 LabmdicSql 99%

LambdicSql.MySql

LambdicSql.SQLite

LambdicSql.Oracle

LambdicSql.DB2

LambdicSql.Npgsql

Page 9: Dot netconf2017 - VS拡張

もっと仲間が欲しいのです!

戦いは数だよ兄貴!

Page 10: Dot netconf2017 - VS拡張

もし わしの味方になれば世界(実装)の半分を わけてやろう・・・

この世の全てのSQLをC#で表現してやる!

仲間募集中!

Page 11: Dot netconf2017 - VS拡張

VS拡張の話

ようやく・・・

Page 12: Dot netconf2017 - VS拡張

Quick shot を作るには?

・右クリックメニューを表示・ドッキングウィンドウを表示・VS2015にも対応・ソリューションビルド・選択位置の関数の情報を取得・追加コードのコンパイル・関数実行

Page 13: Dot netconf2017 - VS拡張

新規にVSIXプロジェクトを作成する

Page 14: Dot netconf2017 - VS拡張

Visual Studio 2017 で VSIXプロジェクトを作成する

Page 15: Dot netconf2017 - VS拡張

作成直後

ビルドして実行すると拡張をデバッグする用のVSが起動する

Page 16: Dot netconf2017 - VS拡張

右クリックメニュー

Page 17: Dot netconf2017 - VS拡張

右クリメニュー用のコマンド追加

Page 18: Dot netconf2017 - VS拡張

ビルド→起動

デフォルトではツールメニュー以下で表示される

押すとメッセージが出る

RClickCommand.csにサンプルコードが書かれていて、そこにメッセージを表示するコードがある

Page 19: Dot netconf2017 - VS拡張

Vsctファイル その前に名前を変更する(任意)

・そもそも、最初に作ったコマンド名がファイル名になっているのでファイル名を変更する。

RClickCommandPackage.vsct→ExTest.vsctRClickCommandPakage.cs → ExtTestPackage.cs

・見通しが悪いのでコメントをすべて消す。

・識別子の名前も変更guidRClickCommandPackage → guidTestExPackageguidRClickCommandPackageCmdSet → guidExTestCmdSetMyMenuGroup → CodeEditorGroup

Page 20: Dot netconf2017 - VS拡張

<Groups><Group guid="guidExTestCmdSet" id="CodeEditorGroup" priority="0x0600">

<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/></Group>

</Groups>

Vsctファイル エディタ上で右クリックで表示されるようにする

<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>

https://msdn.microsoft.com/ja-jp/library/microsoft.visualstudio.shell.vsmenus.aspx

C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VSSDK\VisualStudioIntegration\Common\Inc\vsshlids.h

vsshlids.hに定義されている IDM_VS_ で始まる識別子をいくつか試してみる

ソースコードの右クリックメニュー以外で表示したい場合は・・・

<Extern href="stdidcmd.h"/><Extern href="vsshlids.h"/>

vsctファイルの先頭でインクルードされている

Page 21: Dot netconf2017 - VS拡張

Vsctファイル ついでにショートカットキーもつける

<KeyBindings><KeyBinding guid="guidExTestCmdSet" id="RClickCommandId“editor="guidVSStd97" key1="Z" mod1="Control Shift" />

</KeyBindings>

https://msdn.microsoft.com/ja-jp/library/cc138531.aspx

guidVSStd97が何を意味するのかは知らん

これを入れる

</CommandTable> ←これが閉じる前くらいに入れる

Page 22: Dot netconf2017 - VS拡張

Vsctファイル ついでにアイコンも変える

<Icon guid="guidImages" id="bmpPic1" />

<Bitmaps><Bitmap guid="guidImages" href="Resources\RClickCommand.png" usedList="bmpPic1, …"/>

</Bitmaps>

って書いてるので

RClickCommand.pngの最初の16×16に好きな絵を張り付ける

Page 23: Dot netconf2017 - VS拡張

こんな感じになります

Page 24: Dot netconf2017 - VS拡張

ドッキングウィンドウ

Page 25: Dot netconf2017 - VS拡張

ドッキングウィンドウ追加

追加はできるが・・・

Page 26: Dot netconf2017 - VS拡張

ビルド・・・

おい!

Page 27: Dot netconf2017 - VS拡張

Image?

ビルド・・・

Page 28: Dot netconf2017 - VS拡張

修正・・・

←削除

ExTest.vsctも変更する

新たに追加されたImage系の定義を削除してRClickCommandと同じものを使うようにする

どうやら、生成された

MyDockingWindowCommand.pngがゴミっている。Paintとかでも開けない。

Image差し替えてもいいよ

Page 29: Dot netconf2017 - VS拡張

(気を取り直して)ビルド→起動

表示→その他ウィンドウ→MyDockingWindow

デフォルトではフローティングで表示される

Page 30: Dot netconf2017 - VS拡張

アウトプットにドッキング表示されるようにする

[ProvideToolWindow(typeof(MyDockingWindow), Style = VsDockStyle.Tabbed, Window = ToolWindowGuids.Outputwindow)]public sealed class ExtTestPackage : Package

ExtTestPackageの属性に赤字のコードを足す

Page 31: Dot netconf2017 - VS拡張

ここで一旦、VS2015対応

Page 32: Dot netconf2017 - VS拡張

source.extension.vsixmanifest

ギャラリーにUpしたときに、この情報を使ってアイコンとか表示してくれる。リリースの時にVersionを上げておくとダウンロードした人が更新インストールできる(上げてないと、一回アンインストールが必要だし、そもそもバージョンアップされたかわからない

Page 33: Dot netconf2017 - VS拡張

source.extension.vsixmanifest 2015対応

14(2015)から対応していて16(201x)には対応していませんって意味らしい

[14.0, 16.0)

Page 34: Dot netconf2017 - VS拡張

source.extension.vsixmanifest 2015対応

Page 35: Dot netconf2017 - VS拡張

source.extension.vsixmanifest 2015対応

Visual Studio MPF 15.0 を消す

Page 36: Dot netconf2017 - VS拡張

これで終わりかと思いきや・・・

Page 37: Dot netconf2017 - VS拡張

参照関係を修正する VS2015対応

←赤枠の参照を消す

↧全部Nugetで消します依存関係がある。左のツリーの上から消すと上手く消える

Page 38: Dot netconf2017 - VS拡張

代わりに

Microsoft.VisualStudio.Shell.14.0を入れる

参照関係を修正する VS2015対応

Page 39: Dot netconf2017 - VS拡張

VS2015にインストールしてみる

2015対応大変やった・・・

Page 40: Dot netconf2017 - VS拡張

実装編

Page 41: Dot netconf2017 - VS拡張

Visual Stuidoの機能にアクセスする

DTEを使ってVS自体を操作します。色々できるようですが、この資料では

・Solution・ActiveDocument・Debugger

に触れてみます。その他のもDTE2の定義を見て勘で使ってみてください。

ググり力が重要・・・

var dte = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE2;

Page 42: Dot netconf2017 - VS拡張

プロジェクトをビルドする

dte.Solution. SolutionBuildが使えそうだなー

public interface SolutionBuild{void BuildProject(string SolutionConfiguration,

string ProjectUniqueName,bool WaitForBuildToFinish = false);

いやいや、SolutionConfigrationって何入れたらええねん・・・

Page 43: Dot netconf2017 - VS拡張

var doc = dte.ActiveDocument;if (doc == null) return false;

//選択されているビルドのモード(Debug|AnyCpu)var solutionBuild = DTE.Solution.SolutionBuild;var buildConfig = solutionBuild.ActiveConfiguration.Name;

//選択されているプロジェクト名称var proUniquName = doc.ProjectItem.ContainingProject.UniqueName;

//選択されているプラットフォームvar platform = solutionBuild.ActiveConfiguration.

SolutionContexts.Cast<SolutionContext>().FirstOrDefault().PlatformName;

if (platform == "Win32") platform = "x86";

//ビルドsolutionBuild.BuildProject(buildConfig + "|" + platform, proUniquName, false);

試行錯誤の末、何とかたどりつく・・・

Page 44: Dot netconf2017 - VS拡張

なんかダメ!

ビルドできるんだけど、複数プロジェクトがあるときにアウトプットに変なログが出る(手元にログ残してない。ごめん

どうすりゃいいんだよ!

Page 45: Dot netconf2017 - VS拡張

ググったら出てくる

dte.ExecuteCommand("Build.BuildSelection", "");

なんじゃそれ・・・

Page 46: Dot netconf2017 - VS拡張

//ビルド > ソリューションのビルドならばDTE.ExecuteCommand("Build.BuildSolution");

//ビルド > ソリューションのリビルドならばDTE.ExecuteCommand("Build.RebuildSolution");

//ビルド > xxxのビルドDTE.ExecuteCommand("Build.BuildSelection");

//ビルド > xxxのリビルドDTE.ExecuteCommand("Build.RebuildSelection");

http://microsoft.public.jp.dotnet.languages.vc.narkive.com/pukiYoAo

ちなみに、こうらしい

Page 47: Dot netconf2017 - VS拡張

public interface _Solution : IEnumerable{

Project Item(object index);IEnumerator GetEnumerator();void SaveAs(string FileName);Project AddFromTemplate(string FileName, string Destination, string ProjectName, bool Exclusive = false);Project AddFromFile(string FileName, bool Exclusive = false);void Open(string FileName);void Close(bool SaveFirst = false);void Remove(Project proj);string get_TemplatePath(string ProjectType);object get_Extender(string ExtenderName);void Create(string Destination, string Name);ProjectItem FindProjectItem(string FileName);string ProjectItemsTemplatePath(string ProjectKind);DTE DTE { get; }DTE Parent { get; }int Count { get; }string FileName { get; }Properties Properties { get; }bool IsDirty { get; set; }string FullName { get; }bool Saved { get; set; }Globals Globals { get; }AddIns AddIns { get; }object ExtenderNames { get; }string ExtenderCATID { get; }bool IsOpen { get; }SolutionBuild SolutionBuild { get; }Projects Projects { get; }

}

Solution

ビルドではイマイチやったけどプロジェクトの一覧取ったりソリューション全体を操作できて便利な子ではあります。

Page 48: Dot netconf2017 - VS拡張

右クリックした位置にある関数情報の取得

Page 49: Dot netconf2017 - VS拡張

クリックした位置を取得 dte.ActiveDocument

var csFile = Path.Combine(dte.ActiveDocument.Path, dte.ActiveDocument.Name);

//ファイルを読むvar csLines = File.ReadAllLines(csFile);

//選択位置取得var sel = dte.ActiveDocument.Selection as TextSelection;var pos = GetPos(csLines, sel.CurrentLine - 1, sel.CurrentColumn - 1);

static int GetPos(string[] lines, int currentLine, int currentCol){

int charCount = 0;for (int i = 0; i < lines.Length; i++){

if (i == currentLine){

return charCount + currentCol;}charCount += lines[i].Length;charCount += Environment.NewLine.Length;

}return -1;

}

dte.ActiveDocumentを使う

Page 50: Dot netconf2017 - VS拡張

Roslyn

Microsoft.CodeAnalysis

Page 51: Dot netconf2017 - VS拡張

//Roslynで解析var tree = CSharpSyntaxTree.ParseText(string.Join(Environment.NewLine, csLines));

//選択クラスvar classSyntaxs = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().

//含まれているWhere(x => x.Span.Contains(pos));

//ネームスペースvar namespaceSyntax = tree.GetRoot().DescendantNodes().OfType<NamespaceDeclarationSyntax>().

//先頭FirstOrDefault();

//選択メソッドvar methodSyntax = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().

//含まれているWhere(x => x.Span.Contains(pos)).//先頭FirstOrDefault();

選択位置の関数の型情報的なものを取得 Roslyn

Page 52: Dot netconf2017 - VS拡張

もっといい方法があるかも

//ネームスペースvar namespaceName = namespaceSyntax.Name.GetText().ToString().Trim();

//クラスvar className = string.Join("+", classSyntaxs.Select(x => x.Identifier.Text.Trim()));

//型完全名var typeFullName = namespaceName + "." + className;

//関数名var methodName = methodSyntax.Identifier.Text.Trim();

//戻り値(不完全な情報)var returnType = methodSyntax.ReturnType.ToFullString().Trim();

//引数(不完全な情報)var argumentTypes = new List<string>();var argumentNames = new List<string>();foreach (var e in methodSyntax.ParameterList.Parameters){

argumentTypes.Add(e.Type.ToFullString().Trim());argumentNames.Add(e.Identifier.Text.Trim());

}

選択位置の関数の型情報的なものを取得 Roslyn

Page 53: Dot netconf2017 - VS拡張

ちなみに、2015だと(ていうかVSの持っているRoslynと)同一AppDomainに複数のRoslynのdllがロードされるけど大丈夫みたい。

へー

Page 54: Dot netconf2017 - VS拡張

型情報を得るMono.Cecil

ここでは普通のリフレクションは使いづらい

Page 55: Dot netconf2017 - VS拡張

型情報を得る

アセンブリのパスを取得

もっといい方法があるかも

var proj = dte.ActiveDocument.ProjectItem.ContainingProject.FileName;var solutionBuild = dte.Solution.SolutionBuild;

//選択されているビルドのモード(Debug)var buildConfig = solutionBuild.ActiveConfiguration.Name;

//選択されているプラットフォームvar platform = solutionBuild.ActiveConfiguration.

SolutionContexts.Cast<SolutionContext>().FirstOrDefault().PlatformName;

//CSファイル解析は端折ります・・・ XML解析です。

//出力フォルダ取得var output = CSProjAnalyzer.GetOutputDirectory(proj, buildConfig, platform);

//拡張子var ext = CSProjAnalyzer.GetTargetFileExtension(proj);

//バイナリパスvar assembly = Path.Combine(output, CSProjAnalyzer.GetAssemblyName(proj) + "." + ext);

Page 56: Dot netconf2017 - VS拡張

型情報を得る Mono.Cecil

//アセンブリ情報取得var asm = AssemblyDefinition.ReadAssembly(assemblyPath);

//タイプvar type = asm.Modules.SelectMany(e => e.Types).

Where(e => e.FullName == typeFullName).FirstOrDefault();

//完全なマッチロジックにはならないが、実用上問題ないレベルではある・・・var methodInfo = type.Methods.Where(e => e.Name == methodName).

Where(e => IsMatchMethod(e, methodName, argumentTypes)).FirstOrDefault();

割り切った

Page 57: Dot netconf2017 - VS拡張

private static bool IsMatchMethod(MethodDefinition methodInfo, string methodName, List<string> argumentTypes){

if (methodInfo.Name != methodName) return false;if (methodInfo.Parameters.Count != argumentTypes.Count) return false;for (int i = 0; i < methodInfo.Parameters.Count; i++){

if (!IsMatchType(methodInfo.Parameters[i].ParameterType, argumentTypes[i])) return false;}return true;

}

static bool IsMatchType(TypeReference type, string typeName){

var types1 = GetAllTypes(type);var types2 = GetAllTypes(typeName);if (types1.Length != types2.Length) return false;for (int i = 0; i < types1.Length; i++){

if (!types1[i].Contains(types2[i])) return false;}return true;

}

static string[] GetAllTypes(string type){

return type.Replace(">", "").Split(new[] { "<", "," }, System.StringSplitOptions.RemoveEmptyEntries).Select(e => AdjustTypeName(e)).ToArray();}

static string[] GetAllTypes(TypeReference type){

var types = new List<string>();if (type.IsGenericInstance){

types.AddRange(GetAllTypes(type.GetElementType()));foreach (var e in ((dynamic)type).GenericArguments){

types.AddRange(GetAllTypes(e));}

}else{

//Innerクラスの表現が違うので合わせるtypes.Add(type.FullName.Replace("/", "+"));

}return types.ToArray();

}

static string AdjustTypeName(string type){

type = type.Trim();var arrayCount = GetArrayCount(type);type = type.Replace("[]", string.Empty);switch (type){

case "byte": type = typeof(byte).FullName; break;case "char": type = typeof(char).FullName; break;case "short": type = typeof(short).FullName; break;case "ushort": type = typeof(ushort).FullName; break;case "int": type = typeof(int).FullName; break;case "uint": type = typeof(uint).FullName; break;case "long": type = typeof(long).FullName; break;case "ulong": type = typeof(ulong).FullName; break;case "float": type = typeof(float).FullName; break;case "double": type = typeof(double).FullName; break;case "decimal": type = typeof(decimal).FullName; break;case "string": type = typeof(string).FullName; break;

}return type + string.Join("", Enumerable.Range(0, arrayCount).Select(e => "[]"));

}

static int GetArrayCount(string type){

int count = 0;while (true){

int index = type.IndexOf("[]");if (index == -1) break;count++;type = type.Substring(index + "[]".Length);

}return count;

}

IsMatchMethodは関数名と引数から、(だいたい)マッチしてるか判別するロジックです。

Page 58: Dot netconf2017 - VS拡張

実行 FullDotNet編

Page 59: Dot netconf2017 - VS拡張

VS

Host.exe起動(ファイルで情報を渡す)

コンパイル

リフレクションで実行

デバッグなら待ち

結果取得(ファイル)

構成

Page 60: Dot netconf2017 - VS拡張

Host.exeはリソースに仕込みました。

実行前に、存在しないかバイナリが異なればコピーする

C:¥ProgramData¥QuickShot

Page 61: Dot netconf2017 - VS拡張

リフレクションはアセンブリの解決が必要

C:\ProgramData\QuickShot

QuickShot.ExecutionHost.exe

対象プロジェクトのDebug or Releaseフォルダ

対象のdll群

ここにあるもの以外は解決できない

Page 62: Dot netconf2017 - VS拡張

class AssemblyResolver{

static string[] _dllDirectories;

internal static void Init(string[] dllDirectories){

_dllDirectories = dllDirectories;AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainAssemblyResolve;

}

static Assembly CurrentDomainAssemblyResolve(object sender, ResolveEventArgs args){

var sep = args.Name.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);foreach (var e in _dllDirectories){

var path = Path.Combine(e, sep[0] + ".dll");if (File.Exists(path)){

return Assembly.LoadFrom(path);}path = Path.Combine(e, sep[0] + ".exe");if (File.Exists(path)){

return Assembly.LoadFrom(path);}

}return null;

}}

AppDomain.CurrentDomain.AssemblyResolve を使います

やったことないけどプロービング設定でも行けるかも

Page 63: Dot netconf2017 - VS拡張

コンパイルはRoslynを内部的に使ったCodeDom

最初から素直にRoslynにしておけば良かった・・・

https://opcdiary.net/?p=32908

CSharpCodeProvider codeProvider = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();

Microsoft.CodeDom.Providers.DotNetCompilerPlatform

Page 64: Dot netconf2017 - VS拡張

Roslyn/Binフォルダが必要です。

Asp.Netのプロジェクト作るとできているのでそれをコピります

Bin/Release/Roslyn/Binとかに置く今回はこれもResourcesに入れてProgramData以下にコピった。

最初から素直にRoslynにしておけば良かった・・・

Page 65: Dot netconf2017 - VS拡張

デバッグはこんな感じで実現しました。

Host.exe

VS

if (info.IsAttach){

while (!System.Dianostics.Debugger.IsAttached){

Thread.Sleep(50);}

}

EnvDTE.Processes processes = DTE.Debugger.LocalProcesses;foreach (EnvDTE.Process proc in processes){

if (proc.ProcessID == hostProcessId){

proc.Attach();return;

}}

Page 66: Dot netconf2017 - VS拡張

実行 DotNetCore、DotNetStandard編

Page 67: Dot netconf2017 - VS拡張

リフレクションが上手くいかん!

なんでこんな仕様にしたんだよ・・・

deps.jsonってのがあってそこにないものはロードできない・・・

Page 68: Dot netconf2017 - VS拡張

リフレクションだけでなんとかできる気がしない・・・

・Deps.jsonを書き換えるのはしんどい

・そもそもdllが分散配置されてて解決するもの大変(binフォルダにコピられてない)

Page 69: Dot netconf2017 - VS拡張

方針

Host.exeは対象のプロジェクトごとにコードを作成、コンパイルする

でも、できるだけキャッシュするようにしたんですよ・・・

Page 70: Dot netconf2017 - VS拡張

csproj作成

ファイルは同一フォルダにいれたらOK

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup>

<OutputType>Exe</OutputType><TargetFramework>netcoreapp1.1</TargetFramework><ApplicationIcon /><StartupObject />

</PropertyGroup>

<ItemGroup><PackageReference Include="Newtonsoft.Json" Version="10.0.3" /><PackageReference Include="System.Runtime.Loader" Version="4.3.0" />

</ItemGroup>

<ItemGroup><ProjectReference Include = "c:\work\StandardTest\StandardTest.csproj" />

</ItemGroup></Project>

DotNetCoreのcsprojはシンプル

↑対象のに合わせる

↧host.exeで使う参照

↧対象プロジェクトへのフルパス

Page 71: Dot netconf2017 - VS拡張

ビルド、実行はdotnetexeを使う

あれ?今日のチャックさんの話きいたらRunだけでよかったんじゃ・・・

コマンドラインの情報

https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet?tabs=netcore2x

dotnet restoredotnet builddotnet 対象.dll

今回使ったのは以下

Page 72: Dot netconf2017 - VS拡張

Restore 実行

WorkDirの設定がポイント

var exeOutput = new List<string>(); var p = Process.Start(new ProcessStartInfo{

FileName = "dotnet",Arguments = "restore",WorkingDirectory = workDir,UseShellExecute = false,CreateNoWindow = true,RedirectStandardOutput = true

});p.OutputDataReceived += (_, e) =>{

exeOutput.Add(e.Data);};p.BeginOutputReadLine();p.WaitForExit();

Page 73: Dot netconf2017 - VS拡張

Builld実行

出力も取っておく

var p = Process.Start(new ProcessStartInfo{

FileName = "dotnet",Arguments = "build" + (isDebug ? string.Empty : " -c Release"),WorkingDirectory = workDir,UseShellExecute = false,CreateNoWindow = true,RedirectStandardOutput = true

});p.OutputDataReceived += (_, e) =>{

exeOutput.Add(e.Data);};p.BeginOutputReadLine();p.WaitForExit();

Page 74: Dot netconf2017 - VS拡張

処理実行

他のもそうだけど、待ちは非同期で実行してメインスレッドを固めないようにしました。デバッグもできなくなるしね

var p = Process.Start(new ProcessStartInfo{

FileName = "dotnet",Arguments = isAttach ? "QuickShotExecuter.dll -a" : "QuickShotExecuter.dll",WorkingDirectory = targetDllDir,UseShellExecute = false,CreateNoWindow = true,

}); p.WaitForExit();

Page 75: Dot netconf2017 - VS拡張

QuickShotのTODO

・DotNetCore、DotNetStandardをもう少し速くしたい

・Xamarinとかも対応できないかなー

Page 76: Dot netconf2017 - VS拡張

最後になりましたが、QuickShotのInternal なオブジェクトを生成する部分の実装はneue.ccさんの ChainingAssertionのDynamicAccessorの実装大幅にパクりました。

あざっす!

謝辞

Page 77: Dot netconf2017 - VS拡張

・Friendlyhttps://github.com/Codeer-Software/Friendly.Windows

・LambdicSqlhttps://github.com/Codeer-Software/LambdicSql

・QuickShothttps://marketplace.visualstudio.com/items?itemName=ishikawa-tatsuya.Quickshot

みんな使ってね!

ご清聴ありがとうございました!