Visual Studioでプロジェクトをビルドする際に、複雑な前処理・後処理を記述する場合、通例バッチコマンドによるカスタマイズをします。ただ、Windowsのコマンドは貧弱で、Unix/Linux環境のシェルなどとは比べ物になりません。
従来のバッチコマンドの代わりにPowerShellを使うのが近代的なWindowsプログラマーですが、個人的にはPowerShellの文法が好きではありません。言語機能も従来のバッチコマンドと比べると遥かに柔軟かつ高機能ですが、我々の大好きなC#言語と比べるとかなり書きづらいです。できればPowerShellよりもF#スクリプトやC#スクリプトを使いたいのですが、これらはOS機能として統合・標準化されていないのが難点です。
そこで、PowerShellからC#コンパイラを使い、C#のソースコード文字列を渡してコンパイルし、C#で書かれたクラスをPowerShellから利用するという方法をとってみます。
param($rootDir)
$assemblies = (
"Microsoft.CSharp"
)
$source = @"
using System;
using System.Runtime.CompilerServices;
public static class Test
{
public static void CheckLambdaSpec()
{
var data = new[] { 1, 2, 3, 4, 5 };
Action a = null;
foreach (var x in data)
{
a += () => Console.WriteLine(x);
}
a();
}
public static void DoCallerInfoTestImpl([CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
Console.WriteLine(string.Format("Member name = \"{0}\"", memberName));
Console.WriteLine(string.Format("Source file path = \"{0}\"", sourceFilePath));
Console.WriteLine(string.Format("Source line number = {0}", sourceLineNumber));
}
public static void DoCallerInfoTest()
{
DoCallerInfoTestImpl();
}
public static void DoTest(string dir)
{
//string path = System.IO.Path.Combine(System.IO.Path.Combine(dir, @"Properties"), @"AssemblyInfo.cs");
//using (System.IO.StreamReader reader = new System.IO.StreamReader(path))
var path = System.IO.Path.Combine(dir, @"Properties", @"AssemblyInfo.cs");
using (var reader = new System.IO.StreamReader(path))
{
string line;
//Console.WriteLine(line?.Length.ToString() ?? "null");
dynamic x = "hoge";
Console.WriteLine(x.Length);
while ((line = reader.ReadLine()) != null)
{
if (line.StartsWith("[assembly: AssemblyVersion("))
{
Console.WriteLine(line);
break;
}
}
}
}
}
"@
try
{
$rootDir
$rootDir.Length
Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $source -Language CSharp
[Test]::DoTest($rootDir)
[Test]::DoCallerInfoTest()
}
catch
{
Write-Error($_.Exception.Message)
exit -1
}
上記のPowerShellスクリプトをプロジェクトディレクトリに"test.ps1"として保存し、ビルド前あるいはビルド後イベントのコマンドラインとして、
powershell -ExecutionPolicy RemoteSigned -File "$(ProjectDir)test.ps1" "$(ProjectDir)\" ";exit $LASTEXITCODE"
を入力しておきます。
ここで、Visual Studio 環境変数を PowerShell スクリプトのコマンドライン引数として渡すとき、"$(ProjectDir)\" などとします。"$(ProjectDir)" ではダメなようです。末尾になぜか余計なダブルクォーテーションが入ります。