====== C# Tips======
===== メンバ名を文字列で取得したい =====
''nameof''で取れる。''nameof''が使えなければ、Expressionとラムダ式を組み合わせると取れる。
===== コマンドラインオプションを解析したい =====
[[http://www.ndesk.org/Options|NDesk.Options]]が超便利。MIT/X11ライセンスなのも素敵。
===== Excel.Applicationがゾンビプロセスになる問題の対策 =====
''Microsoft.Office.Interop.Excel.Application''でエクセルのシートを操作中に、例外などで異常終了すると''excel.exe''がゾンビプロセス化し残り続ける事がある。更に悪い事に''Excel.Application''のプロセスはタスクバーには表れないので、気づいた時には大量のゾンビ''excel.exe''が存在し、1つずつタスクマネージャで殺していく簡単なお仕事に追われることになる。
この問題は中々根が深くて──というか原因はCOMの解放漏れなんだけど、解放漏れがCでいう所の''free''し忘れなんて明白なものではなく“コードの書き方”ひとつで出来てしまうのが困り物。というわけで、少々行儀は悪いが強制的にガベコレを走らせ、それでもプロセスが残っていたらkillする方向で対策する。
class KillExcelApp
{
using Excel = Microsoft.Office.Interop.Excel;
void ProcExcel()
{
Excel.Application excelApp = null;
System.Diagnostics.Process excelProcess = null;
try
{
excelApp = new Excel.Application();
excelProcess = GetExcelProcess(excelApp);
// Excel.Applicationを使った処理
...
// Excel.Applicationを閉じる
excelApp.Quit();
excelApp = null;
// 念のため待ってみる
System.Threading.Thread.Sleep(2000);
GC.Collect();
System.Threading.Thread.Sleep(2000);
}
finally
{
GC.Collect();
// Excelが残ってたら強制終了
if (excelProcess.HasExited == false)
{
excelProcess.Kill();
}
}
}
[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
System.Diagnostics.Process GetExcelProcess(Excel.Application excelApp)
{
int id;
GetWindowThreadProcessId(excelApp.Hwnd, out id);
return System.Diagnostics.Process.GetProcessById(id);
}
}
他にいい方法があったら教えてください。
参考サイト:
* [[https://social.msdn.microsoft.com/Forums/ja-jp/0f210f52-3667-4e66-9dd6-4480eede48de/c-excel-exe?forum=csharpgeneralja|C# Excel 操作 EXEが残り続ける]]
* [[http://stackoverflow.com/questions/8490564/getting-excel-application-process-id|c# - Getting excel application process id - Stack Overflow]]
===== ファイルの上書きコピーでUnauthorizedAccessExceptionが出る =====
パーミッション的には全く問題ない場所で、''System.IO.File.Copy''で新たにファイルをコピーしたあと、同じファイルに上書きコピーしようとすると''System.UnauthorizedAccessException''例外が発生する事がある。
そんな時は''Copy''で作成したファイルに対して''File.SetAttributes(file, FileAttributes.Normal)''してやる。
===== enumを64ビットフラグとして使う =====
C#の列挙型は何もしなければint型なので32bit以上の値は扱えないが、''long''ないし''ulong''でenumを作る(正しいC#用語は何と言うんだろう?)と64bitになる。更にフラグの定義では「1L」を使うのがミソ。ただの「1」だと32bit値と見なされ、32ビット以上のシフトが回転してしまう。
enum Flag64 : long
{
Bit0 = 1 << 0,
Bit1 = 1 << 1,
Bit32 = 1 << 32,
Bit33 = 1L << 33,
}
Flag64 b0 = Flag64.b0; // b0 == Flag64.Bit0, (long)b0 == 1
Flag64 b1 = Flag64.b1; // b1 == Flag64.Bit1, (long)b1 == 2
Flag64 b32 = Flag64.b32; // b32 == Flag64.Bit0, (long)b32 == 1
Flag64 b33 = Flag64.b33; // b33 == Flag64.Bit33, (long)b33 == 8589934592