ProcessのインスタンスをDisposeする

# ProcessのインスタンスってDisposableだよね？

だから…

```C#
Process proc = Process.GetCurrentProcess();
Console.WriteLine(proc.Id);
proc.Dispose();
```

って書けば良いよね
でも、こういう時の為に```using```構文がある

```C#
using(Process proc = Process.GetCurrentProcess()) {
    Console.WriteLine(proc.Id);
}
```

みたいな感じでスッキリおっけー

# 対象が配列だったらどうすれば…

つまり…

```C#
foreach(Process proc in Process.GetProcesses()) {
    Console.WriteLine(proc.Id);
    proc.Dispose();
}
```

んー
だと、```Dispose()```がいまいち不安なので、敢えて書くとこんな感じ？

```C#
foreach(Process proc in Process.GetProcesses()) {
    try {
        Console.WriteLine(proc.Id);
    }
    finally {
        proc.Dispose();
    }
}
```

あれー？　なんか一世代巻き戻った感じ…
こういう時の為に```using```構文があるんだけど、どうやって組み込めば良いんだろう？

海外でも疑問に思われる方達はいっぱいおられる様で、例えば[ここら辺](https://stackoverflow.com/questions/16957320/what-does-process-dispose-actually-do)

# でも、大丈夫

[ここ](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/using-statement)にヒントがある
別に```usingステートメント```でインスタンスを取得しなくても、既出のインスタンスをただ置くだけ…
と云う書き方も可能

```C#
foreach(Process proc in Process.GetProcesses()) {
    using(proc) {
        Console.WriteLine(proc.Id);
    }
}
```

ただし、これはベストプラクティスではない、とも書いてある
何故なら

```C#
foreach(Process proc in Process.GetProcesses()) {
    using(proc) {
        Console.WriteLine(proc.Id);
    }   //  <== procはここでDisposeされる　　ので、procの中身は無効
　　//      <== ここでprocにはアクセス可能　　な為、不正なprocを参照できちゃう
}
```

# うん、じゃぁこうしよう

```C#
foreach(Process proc in Process.GetProcesses())
    using(proc) {
        Console.WriteLine(proc.Id);
    }
```

foreachの中身をusingステートメント単体だけに簡素化する事で、procのDispose後の隙間を作らない
まぁ、コーディングレベルの規約となるので「ベスト」な「プラクティス」ではない、と言われればそうかも知れないですけど…
ま、私個人としては、次善の策としてProcessインスタンスのDispose問題には結論が出たかな？
と一段落

# もうちょっと踏み込んでみる

でも、本当にProcessインスタンスのDisposeは有効なんですよね？
MSのサイトにそう書いてあるんだから疑う必要はないんだろうけど、内部ではいったい何が起こっているかを掘り下げて、もう一段留飲を下げてみたいな、と

そこで、以下の単純なスニペットをILレベルで比較してみたいと思う

```C#:snippet#1
using(Process proc = Process.GetCurrentProcess()) {
	Console.WriteLine(proc.Id);
}
```

と

```C#:snippet#2
Process proc = Process.GetCurrentProcess();
using(proc) {
	Console.WriteLine(proc.Id);
}
```

# ＩＬの比較

ここでは、ILソースを手修正して比較し易く改変してあります

```IL:snippet#1
.method private hidebysig static 
	void Main (
		string[] args
	) cil managed 
{
	// Method begins at RVA 0x2050
	// Header size: 12
	// Code size: 35 (0x23)
	.maxstack 1
	.entrypoint
	.locals init (
		[0] class [System]System.Diagnostics.Process proc
	)

	// {
	IL_0000: nop
	// using Process process = Process.GetCurrentProcess();
	IL_0001: call class [System]System.Diagnostics.Process [System]System.Diagnostics.Process::GetCurrentProcess()
	IL_0006: stloc.0
	.try
	{
		// Console.WriteLine(process.Id);
		IL_0009: nop
		IL_000a: ldloc.0
		IL_000b: callvirt instance int32 [System]System.Diagnostics.Process::get_Id()
		IL_0010: call void [mscorlib]System.Console::WriteLine(int32)
		IL_0015: nop
		IL_0016: nop
		IL_0017: leave.s IL_0024
	} // end .try
	finally
	{
		IL_0019: ldloc.0
		IL_001a: brfalse.s IL_0023

		IL_001c: ldloc.0
		IL_001d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
		IL_0022: nop

		IL_0023: endfinally
	} // end handler

	IL_0024: ret
} // end of method Program::Main
```

```IL:snippet#2
.method private hidebysig static 
	void Main (
		string[] args
	) cil managed 
{
	// Method begins at RVA 0x2050
	// Header size: 12
	// Code size: 37 (0x25)
	.maxstack 1
	.entrypoint
	.locals init (
		[0] class [System]System.Diagnostics.Process proc,
==> 	[1] class [System]System.Diagnostics.Process
	)

	// {
	IL_0000: nop
	// Process currentProcess = Process.GetCurrentProcess();
	IL_0001: call class [System]System.Diagnostics.Process [System]System.Diagnostics.Process::GetCurrentProcess()
	IL_0006: stloc.0
	// using (currentProcess)
==> IL_0007: ldloc.0
==> IL_0008: stloc.1
	.try
	{
		// Console.WriteLine(currentProcess.Id);
		IL_0009: nop
		IL_000a: ldloc.0
		IL_000b: callvirt instance int32 [System]System.Diagnostics.Process::get_Id()
		IL_0010: call void [mscorlib]System.Console::WriteLine(int32)
		IL_0015: nop
		IL_0016: nop
		IL_0017: leave.s IL_0024
	} // end .try
	finally
	{
==> 	IL_0019: ldloc.1
		IL_001a: brfalse.s IL_0023

==> 	IL_001c: ldloc.1
		IL_001d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
		IL_0022: nop

		IL_0023: endfinally
	} // end handler

	IL_0024: ret
} // end of method Program::Main
```

```snippet#2```の行の先頭に```==>```を付けたところが、有意に異なる場所(5ヶ所)

- 一つ目は、内部変数を一個余計に定義している
- 二つ目三つ目で、内部変数をコピーしている
- 四つ目と五つ目は、Dispose絡みの処理で、変数の参照先が異なっている

なんて、文字で書いても分かり難いので、図示してみる

# snippet#1

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136132/1e404eb6-3172-2f33-3628-7fbbd2c11375.png)


こんな感じ？
```using```抜ける時に```Slot[0]```の変数に対して```Dispose()```掛けて、どっかにあるアンマネージドなリソースの破棄も行われている（筈）

# snippet#2

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136132/bd1ecba1-ff0c-aac1-82ef-cce551665309.png)

```Slot[0]```のローカル変数（```GetCurrentProcess()```したデータ）を、```usingステートメント```が```Slot[1]```に単純コピー
なので、```Process```の唯一のインスタンスを、二つの```Slot```で共有している
```using```を抜ける時には、```Slot[1]```の変数経由で```Dispose()```を掛けている
でも、```Slot[0]```の変数が残っている、けど、```Process```のインスタンスは```Dispose```済み、と云う例の状態が```IL```レベルでも読み取れる

# てな訳で

次善の策としてのコーディング規約を導入することで、プロセス列挙時においてもusingを使ったProcessインスタンスのDisposeを安心して実装できる、と結論付けたい