一般的な使い方
try
{
例外が投げられる可能性のあるコード
}
catch(例外の種類)
{
例外処理コード
}
finally
{
例外発生の有無にかかわらず実行したいコード
リソースの破棄などを行う
}
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
ExceptionClass e = new ExceptionClass();
e.throw_divisionZero();
}
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
using System;
namespace ExceptionSample
{
public class ExceptionClass
{
public void throw_divisionZero()
{
throw new DivideByZeroException();
}
}
}
出力結果:
~~~~~~Entry~~~~~~
~~~~~~try~~~~~~
~~~~~~catch DivideByZeroException~~~~~~
~~~~~~finally~~~~~~
~~~~~~Finish~~~~~~
逆アセンブリ分析
Main関数が三つ分けられている。必ず3回実行される仕組みです。
00007FFC5D660FAD ?? ??????
00007FFC5D660FAE add byte ptr [rax],al
--- E:\099_Technology\C#\csharp_learn\Program.cs -------------------------------
1: using System;
2: using System.IO;
3: using ExceptionSample;
4:
5: namespace csharp_learn
6: {
7: class Program
8: {
9: static void Main(string[] args)
10: {
00007FFC5D660FB0 push rbp
00007FFC5D660FB1 push rdi
00007FFC5D660FB2 push rsi
00007FFC5D660FB3 sub rsp,50h
00007FFC5D660FB7 mov rbp,rsp
00007FFC5D660FBA xor eax,eax
00007FFC5D660FBC mov qword ptr [rbp+40h],rax
00007FFC5D660FC0 mov qword ptr [rbp+38h],rax
00007FFC5D660FC4 mov qword ptr [rbp+30h],rax
00007FFC5D660FC8 mov qword ptr [rbp+48h],rax
00007FFC5D660FCC mov qword ptr [rbp+20h],rsp
00007FFC5D660FD0 mov qword ptr [rbp+70h],rcx
00007FFC5D660FD4 cmp dword ptr [7FFC5D6FFA78h],0
00007FFC5D660FDB je csharp_learn.Program.Main(System.String[])+032h (07FFC5D660FE2h)
00007FFC5D660FDD call 00007FFCBD29D7A0
00007FFC5D660FE2 nop
11: Console.WriteLine("~~~~~~Entry~~~~~~");
00007FFC5D660FE3 mov rcx,2309CE030C0h
00007FFC5D660FED mov rcx,qword ptr [rcx]
00007FFC5D660FF0 call CLRStub[MethodDescPrestub]@7ffc5d660668 (07FFC5D660668h)
00007FFC5D660FF5 nop
12: try
13: {
00007FFC5D660FF6 nop
14: //実行のために、リソースを取得
15: Console.WriteLine("~~~~~~try~~~~~~");
00007FFC5D660FF7 mov rcx,2309CE030C8h
00007FFC5D661001 mov rcx,qword ptr [rcx]
00007FFC5D661004 call CLRStub[MethodDescPrestub]@7ffc5d660668 (07FFC5D660668h)
00007FFC5D661009 nop
16: ExceptionClass e = new ExceptionClass();
00007FFC5D66100A mov rcx,7FFC5D7221D8h
00007FFC5D661014 call CORINFO_HELP_NEWSFAST (07FFCBD177840h)
00007FFC5D661019 mov qword ptr [rbp+38h],rax
00007FFC5D66101D mov rcx,qword ptr [rbp+38h]
00007FFC5D661021 call CLRStub[MethodDescPrestub]@7ffc5d660658 (07FFC5D660658h)
00007FFC5D661026 mov rcx,qword ptr [rbp+38h]
00007FFC5D66102A mov qword ptr [rbp+40h],rcx
17: e.throw_divisionZero();
00007FFC5D66102E mov rcx,qword ptr [rbp+40h]
00007FFC5D661032 cmp dword ptr [rcx],ecx
00007FFC5D661034 call CLRStub[MethodDescPrestub]@7ffc5d660650 (07FFC5D660650h)
00007FFC5D661039 nop
18: }
00007FFC5D66103A nop
00007FFC5D66103B nop
00007FFC5D66103C jmp csharp_learn.Program.Main(System.String[])+08Eh (07FFC5D66103Eh)
22: }
00007FFC5D66103E nop
00007FFC5D66103F jmp csharp_learn.Program.Main(System.String[])+091h (07FFC5D661041h)
00007FFC5D661041 mov rcx,rsp
00007FFC5D661044 call csharp_learn.Program.Main(System.String[])+0EFh (07FFC5D66109Fh)
00007FFC5D661049 nop
28: Console.WriteLine("~~~~~~Finish~~~~~~"); //該当行を実行前に07FFC5D66109Fhのfinallyが先に実行する。
00007FFC5D66104A mov rcx,2309CE030E0h
00007FFC5D661054 mov rcx,qword ptr [rcx]
00007FFC5D661057 call CLRStub[MethodDescPrestub]@7ffc5d660668 (07FFC5D660668h)
00007FFC5D66105C nop
29: }
00007FFC5D66105D nop
00007FFC5D66105E lea rsp,[rbp+50h]
00007FFC5D661062 pop rsi
00007FFC5D661063 pop rdi
00007FFC5D661064 pop rbp
00007FFC5D661065 ret
1: using System;
2: using System.IO;
3: using ExceptionSample;
4:
5: namespace csharp_learn
6: {
7: class Program
8: {
9: static void Main(string[] args)
10: {
00007FFC5D661066 push rbp
00007FFC5D661067 push rdi
00007FFC5D661068 push rsi
00007FFC5D661069 sub rsp,30h
00007FFC5D66106D mov rbp,qword ptr [rcx+20h]
00007FFC5D661071 mov qword ptr [rsp+20h],rbp
19: catch (DivideByZeroException)
00007FFC5D661076 mov qword ptr [rbp+30h],rdx
20: {
00007FFC5D66107A nop
21: Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
00007FFC5D66107B mov rcx,2309CE030D0h
00007FFC5D661085 mov rcx,qword ptr [rcx]
00007FFC5D661088 call CLRStub[MethodDescPrestub]@7ffc5d660668 (07FFC5D660668h)
00007FFC5D66108D nop
22: }
00007FFC5D66108E nop
00007FFC5D66108F nop
00007FFC5D661090 lea rax,[csharp_learn.Program.Main(System.String[])+08Eh (07FFC5D66103Eh)]
00007FFC5D661097 add rsp,30h
00007FFC5D66109B pop rsi
00007FFC5D66109C pop rdi
00007FFC5D66109D pop rbp
00007FFC5D66109E ret
1: using System;
2: using System.IO;
3: using ExceptionSample;
4:
5: namespace csharp_learn
6: {
7: class Program
8: {
9: static void Main(string[] args)
10: {
00007FFC5D66109F push rbp
00007FFC5D6610A0 push rdi
00007FFC5D6610A1 push rsi
00007FFC5D6610A2 sub rsp,30h
00007FFC5D6610A6 mov rbp,qword ptr [rcx+20h]
00007FFC5D6610AA mov qword ptr [rsp+20h],rbp
23: finally
24: {
00007FFC5D6610AF nop
25: //tryで取得したリソースを解放
26: Console.WriteLine("~~~~~~finally~~~~~~");
00007FFC5D6610B0 mov rcx,2309CE030D8h
00007FFC5D6610BA mov rcx,qword ptr [rcx]
00007FFC5D6610BD call CLRStub[MethodDescPrestub]@7ffc5d660668 (07FFC5D660668h)
00007FFC5D6610C2 nop
27: }
00007FFC5D6610C3 nop
00007FFC5D6610C4 nop
00007FFC5D6610C5 add rsp,30h
00007FFC5D6610C9 pop rsi
00007FFC5D6610CA pop rdi
00007FFC5D6610CB pop rbp
00007FFC5D6610CC ret
00007FFC5D6610CD add byte ptr [rax],al
00007FFC5D6610CF add byte ptr [rcx],bl
00007FFC5D6610D1 or al,byte ptr [7FFC64691ADCh]
00007FFC5D6610D7 xchg eax,edx
00007FFC5D6610D8 add esp,dword ptr [rax+2]
00007FFC5D6610DB jo csharp_learn.Program.Main(System.String[])+012Eh (07FFC5D6610DEh)
00007FFC5D6610DD push rax
00007FFC5D6610DE add byte ptr [rax],al
00007FFC5D6610E0 add byte ptr [rax],al
00007FFC5D6610E3 add byte ptr [rcx],bl
00007FFC5D6610E5 ?? ??????
27: }
00007FFC5D6610E6 add al,0
00007FFC5D6610E8 ?? ??????
27: }
00007FFC5D6610E9 push rdx
00007FFC5D6610EA add esp,dword ptr [rax+2]
00007FFC5D6610ED jo csharp_learn.Program.Main(System.String[])+0140h (07FFC5D6610F0h)
00007FFC5D6610EF push rax
00007FFC5D6610F0 add byte ptr [rax],al
00007FFC5D6610F3 add byte ptr [rcx],bl
00007FFC5D6610F5 ?? ??????
27: }
00007FFC5D6610F6 add al,0
00007FFC5D6610F8 ?? ??????
27: }
00007FFC5D6610F9 push rdx
00007FFC5D6610FA add esp,dword ptr [rax+2]
00007FFC5D6610FD jo csharp_learn.Program.Main(System.String[])+0150h (07FFC5D661100h)
00007FFC5D6610FF push rax
00007FFC5D661100 add byte ptr [rax],al
00007FFC5D661103 add byte ptr [rax],al
--- ソース ファイルがありません -------------------------------------------------------------
try-return-catch-finally
tryの中にreturnがあったら、catchとfinallyを実行されるでしょうか。finallyを実行されたとして、finally実行後の関数処理は実行されるか。さっそく検証してみましょう。
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
ExceptionClass e = new ExceptionClass();
return;
e.throw_divisionZero();
}
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
出力結果:
~~~~~~Entry~~~~~~
~~~~~~try~~~~~~
~~~~~~finally~~~~~~
結論をまとめます。
1. tryの中に例外が発生させる前に、returnしているため、例外発生しない。
2. tryの中にreturnしてもfinallyは実行される。
3. tryの中にreturnすると、finally処理後の関数内の処理は実行しない。
4. try-catch-finallyの仕組みは従来の関数の仕組みではない。関数の場合は、return処理すると、関数の処理はが終了してしまう。
try-catch-return-finally
catchの中にreturnすると、finallyの処理が実行されるか。finally実行後の関数処理は実行されるか。
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
ExceptionClass e = new ExceptionClass();
e.throw_divisionZero();
}
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
return;
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
出力結果:
~~~~~~Entry~~~~~~
~~~~~~try~~~~~~
~~~~~~catch DivideByZeroException~~~~~~
~~~~~~finally~~~~~~
結論:
1. catchでreturnがあっても、finallyの処理も実行される。
2. catchでreturnがあれば、finally実行後の関数処理は実行されない。
try-catch-finally-return
finallyの中にreturn句はビルドエラーです。
error CS0157: コントロールが finally 句の本体から出られません
tryのみ使えるか
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
//ExceptionClass e = new ExceptionClass();
//e.throw_divisionZero();
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
ビルドエラー
error CS1524: catch または finally が必要です
catchのみ使えるか
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
return;
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
ビルドエラー
error CS1003: 構文エラーです。’try’ が必要です
finallyのみ使えるか
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
ビルドエラー
error CS1003: 構文エラーです。’try’ が必要です
try-catchのみ使えるか
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
ExceptionClass e = new ExceptionClass();
e.throw_divisionZero();
}
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
出力結果:
~~~~~~Entry~~~~~~
~~~~~~try~~~~~~
~~~~~~catch DivideByZeroException~~~~~~
~~~~~~Finish~~~~~~
try-finallyのみ使えるか
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
出力結果:
~~~~~~Entry~~~~~~
~~~~~~try~~~~~~
~~~~~~finally~~~~~~
~~~~~~Finish~~~~~~
catch-finallyのみ使えるか
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
ビルドエラーです。構文エラーです。’try’ が必要です
try-catch-catch-catch…finally
一つのtryに対して、複数のcatchが可能ですが、catchの優先順位を考慮する必要がある。
優先順位低い例外を一番上に置くべきです。Exceptionを一番上に置いてしまうと、個別の例外処理の実行ができなくなる。
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
ExceptionClass e = new ExceptionClass();
e.throw_divisionZero();
}
catch (IOException)
{
//try実行の中に異常が発生した場合の処理
Console.WriteLine("~~~~~~catch IOException~~~~~~");
}
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
}
catch (Exception)
{
Console.WriteLine("~~~~~~catch Exception~~~~~~");
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
出力結果:
~~~~~~Entry~~~~~~
~~~~~~try~~~~~~
~~~~~~catch DivideByZeroException~~~~~~
~~~~~~finally~~~~~~
~~~~~~Finish~~~~~~
次は、例外のcatchの置き場所を検証しましょう。
スーパー型 (‘Exception’) の例外を一番上に置くと、ビルドエラーになる。
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
ExceptionClass e = new ExceptionClass();
e.throw_divisionZero();
}
catch (Exception)
{
Console.WriteLine("~~~~~~catch Exception~~~~~~");
}
catch (IOException)
{
//try実行の中に異常が発生した場合の処理
Console.WriteLine("~~~~~~catch IOException~~~~~~");
}
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
1>—— ビルド開始: プロジェクト: csharp_learn, 構成: Debug Any CPU ——
1>\Program.cs(24,20,24,31): error CS0160: 前の catch 句はこれ、またはスーパー型 (‘Exception’) の例外のすべてを既にキャッチしました
1>\Program.cs(29,20,29,41): error CS0160: 前の catch 句はこれ、またはスーパー型 (‘Exception’) の例外のすべてを既にキャッチしました
1>プロジェクト “csharp_learn.csproj” のビルドが終了しました — 失敗。
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========
try-catch-catch-finally-finally使えるか
using System;
using System.IO;
using ExceptionSample;
namespace csharp_learn
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("~~~~~~Entry~~~~~~");
try
{
//実行のために、リソースを取得
Console.WriteLine("~~~~~~try~~~~~~");
ExceptionClass e = new ExceptionClass();
e.throw_divisionZero();
}
catch (DivideByZeroException)
{
Console.WriteLine("~~~~~~catch DivideByZeroException~~~~~~");
}
catch (Exception)
{
Console.WriteLine("~~~~~~catch Exception~~~~~~");
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
finally
{
//tryで取得したリソースを解放
Console.WriteLine("~~~~~~finally~~~~~~");
}
Console.WriteLine("~~~~~~Finish~~~~~~");
}
}
}
ビルドエラー error CS1003: 構文エラーです。’try’ が必要です
マイクロソフト公式のtry-catch-finally (C# リファレンス)
通常、catch
および finally
は、try
ブロックのリソースを取得して使用する場合に、対で記述されます。catch
ブロックで例外的な状況を処理し、finally
ブロックでリソースを解放します。
例外の再スローの使用例を含む詳細については、「try-catch」および例外のスローに関するページをご覧ください。 finally
ブロックの詳細については、「try-finally」を参照してください。
参考サイト
https://qiita.com/ts7i/items/d7f6c1cd5a14e55943d4
https://kanda-it-school-kensyu.com/java-basic-contents/jb_ch08/jb_0803/
https://docs.microsoft.com/ja-jp/dotnet/csharp/fundamentals/exceptions/
コメント