Pernyataan penanganan pengecualian - throw
, , try-catch
, try-finally
dan try-catch-finally
Anda menggunakan throw
pernyataan dan try
untuk bekerja dengan pengecualian. throw
Gunakan pernyataan untuk melemparkan pengecualian. try
Gunakan pernyataan untuk menangkap dan menangani pengecualian yang mungkin terjadi selama eksekusi blok kode.
Pernyataan throw
Pernyataan tersebut throw
melemparkan pengecualian:
if (shapeAmount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(shapeAmount), "Amount of shapes must be positive.");
}
Dalam pernyataan throw e;
, hasil ekspresi e
harus secara implisit dapat dikonversi ke System.Exception.
Anda dapat menggunakan kelas pengecualian bawaan, misalnya, ArgumentOutOfRangeException atau InvalidOperationException. .NET juga menyediakan metode pembantu berikut untuk melemparkan pengecualian dalam kondisi tertentu: ArgumentNullException.ThrowIfNull dan ArgumentException.ThrowIfNullOrEmpty. Anda juga dapat menentukan kelas pengecualian Anda sendiri yang berasal dari System.Exception. Untuk informasi selengkapnya, lihat Membuat dan melempar pengecualian.
catch
Di dalam blok, Anda dapat menggunakan throw;
pernyataan untuk melemparkan kembali pengecualian yang ditangani oleh catch
blok:
try
{
ProcessShapes(shapeAmount);
}
catch (Exception e)
{
LogError(e, "Shape processing failed.");
throw;
}
Catatan
throw;
mempertahankan jejak tumpukan asli pengecualian, yang disimpan di Exception.StackTrace properti . Berlawanan dengan itu, throw e;
memperbarui StackTrace properti .e
Ketika pengecualian dilemparkan, runtime bahasa umum (CLR) mencari catch
blok yang dapat menangani pengecualian ini. Jika metode yang dijalankan saat ini tidak berisi blok seperti catch
itu, CLR melihat metode yang disebut metode saat ini, dan seterusnya di atas tumpukan panggilan. Jika tidak ada catch
blok yang ditemukan, CLR mengakhiri utas yang dieksekusi. Untuk informasi selengkapnya, lihat bagian Bagaimana pengecualian ditangani dari spesifikasi bahasa C#.
Ekspresi throw
Anda juga dapat menggunakan throw
sebagai ekspresi. Ini mungkin nyaman dalam sejumlah kasus, yang meliputi:
operator kondisional. Contoh berikut menggunakan
throw
ekspresi untuk melemparkan ArgumentException saat arrayargs
yang diteruskan kosong:string first = args.Length >= 1 ? args[0] : throw new ArgumentException("Please supply at least one argument.");
operator penggabungan-null. Contoh berikut menggunakan
throw
ekspresi untuk melempar ArgumentNullException saat string yang akan ditetapkan ke properti adalahnull
:public string Name { get => name; set => name = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); }
lambda atau metode berisi ekspresi (expression-bodied). Contoh berikut menggunakan
throw
ekspresi untuk melemparkan InvalidCastException untuk menunjukkan bahwa konversi ke DateTime nilai tidak didukung:DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException("Conversion to a DateTime is not supported.");
Pernyataan try
Anda dapat menggunakan try
pernyataan dalam salah satu formulir berikut: try-catch
- untuk menangani pengecualian yang mungkin terjadi selama eksekusi kode di dalam try
blok, try-finally
- untuk menentukan kode yang dijalankan saat kontrol meninggalkan try
blok, dan try-catch-finally
- sebagai kombinasi dari dua formulir sebelumnya.
Pernyataan try-catch
try-catch
Gunakan pernyataan untuk menangani pengecualian yang mungkin terjadi selama eksekusi blok kode. Tempatkan kode di mana pengecualian mungkin terjadi di dalam try
blok. Gunakan klausa tangkapan untuk menentukan jenis dasar pengecualian yang ingin Anda tangani di blok yang catch
sesuai:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
Anda dapat memberikan beberapa klausa tangkapan:
try
{
var result = await ProcessAsync(-3, 4, cancellationToken);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Processing is cancelled.");
}
Ketika pengecualian terjadi, klausul tangkapan diperiksa dalam urutan yang ditentukan, dari atas ke bawah. Maksimum, hanya satu catch
blok yang dijalankan untuk pengecualian yang dilemparkan. Seperti yang juga ditunjukkan oleh contoh sebelumnya, Anda dapat menghilangkan deklarasi variabel pengecualian dan hanya menentukan jenis pengecualian dalam klausa tangkapan. Klausa tangkapan tanpa jenis pengecualian yang ditentukan cocok dengan pengecualian apa pun dan, jika ada, harus menjadi klausa tangkapan terakhir.
Jika Anda ingin melemparkan kembali pengecualian yang tertangkap, gunakan throw
pernyataan , seperti yang ditunjukkan contoh berikut:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e)
{
LogError(e, "Processing failed.");
throw;
}
Catatan
throw;
mempertahankan jejak tumpukan asli pengecualian, yang disimpan di Exception.StackTrace properti . Berlawanan dengan itu, throw e;
memperbarui StackTrace properti .e
when
Filter pengecualian
Bersama dengan jenis pengecualian, Anda juga dapat menentukan filter pengecualian yang memeriksa pengecualian lebih lanjut dan memutuskan apakah blok yang sesuai catch
menangani pengecualian tersebut. Filter pengecualian adalah ekspresi Boolean yang mengikuti when
kata kunci, seperti yang ditunjukkan contoh berikut:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e) when (e is ArgumentException || e is DivideByZeroException)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
Contoh sebelumnya menggunakan filter pengecualian untuk menyediakan satu catch
blok untuk menangani pengecualian dari dua jenis yang ditentukan.
Anda dapat memberikan beberapa catch
klausul untuk jenis pengecualian yang sama jika dibedakan oleh filter pengecualian. Salah satu klausa tersebut mungkin tidak memiliki filter pengecualian. Jika klausa seperti itu ada, klausul tersebut harus menjadi yang terakhir dari klausul yang menentukan jenis pengecualian tersebut.
catch
Jika klausa memiliki filter pengecualian, klausul tersebut dapat menentukan jenis pengecualian yang sama dengan atau kurang diturunkan daripada jenis catch
pengecualian klausa yang muncul setelahnya. Misalnya, jika filter pengecualian ada, catch (Exception e)
klausa tidak perlu menjadi klausa terakhir.
Pengecualian dalam metode asinkron dan iterator
Jika pengecualian terjadi dalam fungsi asinkron, pengecualian akan disebarkan ke pemanggil fungsi saat Anda menunggu hasil fungsi, seperti yang ditunjukkan contoh berikut:
public static async Task Run()
{
try
{
Task<int> processing = ProcessAsync(-1);
Console.WriteLine("Launched processing.");
int result = await processing;
Console.WriteLine($"Result: {result}.");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
// Output:
// Launched processing.
// Processing failed: Input must be non-negative. (Parameter 'input')
}
private static async Task<int> ProcessAsync(int input)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(nameof(input), "Input must be non-negative.");
}
await Task.Delay(500);
return input;
}
Jika pengecualian terjadi dalam metode iterator, pengecualian tersebut disebarkan ke pemanggil hanya ketika iterator maju ke elemen berikutnya.
Pernyataan try-finally
Dalam pernyataan try-finally
, finally
blok dijalankan ketika kontrol meninggalkan try
blok. Kontrol mungkin meninggalkan try
blok sebagai akibat dari
- eksekusi normal,
- eksekusi pernyataan lompat (yaitu, ,
return
,continue
break
, ataugoto
), atau - propagasi pengecualian di
try
luar blok.
Contoh berikut menggunakan finally
blok untuk mengatur ulang status objek sebelum kontrol meninggalkan metode :
public async Task HandleRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
finally
{
Busy = false;
}
}
Anda juga dapat menggunakan finally
blok untuk membersihkan sumber daya yang dialokasikan yang try
digunakan dalam blok.
Catatan
Saat jenis sumber daya mengimplementasikan IDisposable antarmuka atau IAsyncDisposable , pertimbangkan pernyataan .using
Pernyataan ini using
memastikan bahwa sumber daya yang diperoleh dibuang ketika kontrol meninggalkan using
pernyataan. Kompilator mengubah pernyataan menjadi using
try-finally
pernyataan.
Eksekusi finally
blok tergantung pada apakah sistem operasi memilih untuk memicu operasi unwind pengecualian. Satu-satunya kasus di mana finally
blok tidak dijalankan melibatkan penghentian segera program. Misalnya, penghentian tersebut mungkin terjadi karena Environment.FailFast panggilan atau OverflowException InvalidProgramException pengecualian. Sebagian besar sistem operasi melakukan pembersihan sumber daya yang wajar sebagai bagian dari menghentikan dan membongkar proses.
Pernyataan try-catch-finally
Anda menggunakan try-catch-finally
pernyataan untuk menangani pengecualian yang mungkin terjadi selama eksekusi try
blok dan menentukan kode yang harus dijalankan saat kontrol meninggalkan try
pernyataan:
public async Task ProcessRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
catch (Exception e) when (e is not OperationCanceledException)
{
LogError(e, $"Failed to process request for item ID {itemId}.");
throw;
}
finally
{
Busy = false;
}
}
Ketika pengecualian ditangani oleh catch
blok, finally
blok dijalankan setelah eksekusi blok itu catch
(bahkan jika pengecualian lain terjadi selama eksekusi catch
blok). Untuk informasi tentang catch
dan finally
blok, lihat Bagian try-catch
pernyataan dan try-finally
Pernyataan.
Spesifikasi bahasa C#
Untuk informasi selengkapnya, lihat bagian berikut dari spesifikasi bahasa C#: