2016年9月22日木曜日

【C#】【VisualStudio】開始オプションにXMLで勝手に補完される

あまりやらないと思うが、Visual C# 2005 (2015でも大体同じ・・・、おそらくその間のバージョンもそうだろう)で以下のようにコマンドライン引数にxmlを指定して保存すると・・・



slnを開き直した時に、以下のように勝手にネームスペース(xmlns)が追加されてしまう。
設計ミスだろ・・・、これ・・・。勝手に書き換えんな!


少し調べたがこれを直接回避する手段は見つからなかった。
ちなみに、上記のコマンドライン引数の値は以下のcsproj.userに保存される。




単体試験などで引数を指定する場合は、上記では困る。NUnitまたは、VS2012のMStestが使えるならそれらを使えばよいが、使えない場合は、別の方法が必要。

VS2005Pro以上では、デバッグのタブに[外部プログラムの開始]があり、batか何か指定してそれを経由すれば解決できると思われる。しかし、VS2005Express版では、デバッグのタブに[外部プログラムの開始]が存在せず、指定できない。

面倒だが、別プロジェクト(下記のTestDriverなど)を作成して、そこからTmp配下のProgram.Main()を呼び出す。

TestDriverプロジェクトを追加。(プロジェクト名は任意)


TestDriverプロジェクトにTmpプロジェクトの参照を追加。




下記のように参照設定配下にTmpが追加される。


ややこしいがTestDriverとTmpプロジェクト配下にそれぞれ、別のProgramクラスとMain()メソッドが存在している。Main()は大抵publicになってないため、TestDriver.Program.Main()から直接Tmp.Program.Main()は呼び出せない。下記のようにTmp.exeをアセンブリとして、TestDriverにLoadし、そのAssemblyからTmp.Programクラスを取得し、ProgramクラスのMain()をReflectionを使用して呼び出している。

ただし、この方法はTmp.Program.Main(string[] args)というシグネチャの場合(コマンドライン引数をMain関数の引数で持つ場合)のみ可能である。Tmp.Program.Main()というシグネチャ(関数の引数無し)で、System.Environment.GetCommandLineArgs()により、コマンドライン引数を取得している場合はこの方法は使用できない。Invoke時に例外が発生する。

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace TestDriver
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly asm = Assembly.Load(new AssemblyName("Tmp"));
            Type t = asm.GetType("Tmp.Program");
            System.Reflection.MethodInfo minfo = t.GetMethod("Main",
               BindingFlags.Static | BindingFlags.NonPublic);
            minfo.Invoke(minfo, new object[] { new string[] { "<tmp></tmp>" } });
        }
    }
}


デバッガ不要なら以下でもできるが、#ifディレクティブや相対パスが気に入らない。
using System;
using System.Diagnostics;

namespace TestDriver
{
    class Program
    {
        static void Main(string[] args)
        {
#if DEBUG
            string exePath = @"..\..\..\Tmp\bin\debug\Tmp.exe";
#elif RELEASE
            string exePath = @"..\..\..\Tmp\bin\release\Tmp.exe";
#else
#error Please make target configuration!!
#endif
            Process p = Process.Start(exePath, "<tmp></tmp>");
        }
    }
}


0 件のコメント:

コメントを投稿