apa perbedaan antara
try { ... }
catch{ throw }
dan
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Terlepas dari yang kedua menunjukkan pesan?
apa perbedaan antara
try { ... }
catch{ throw }
dan
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Terlepas dari yang kedua menunjukkan pesan?
Jawaban:
throw; rethrows pengecualian asli dan mempertahankan jejak tumpukan aslinya.
throw ex;melempar pengecualian asli tetapi mengatur ulang jejak tumpukan, menghancurkan semua informasi jejak tumpukan sampai catchblok Anda .
throw ex;throw new Exception(ex.Message);bahkan lebih buruk. Ini menciptakan Exceptioncontoh baru , kehilangan jejak tumpukan asli pengecualian, serta jenisnya. (misalnya, IOException).
Selain itu, beberapa pengecualian mengandung informasi tambahan (mis., ArgumentException.ParamName).
throw new Exception(ex.Message); akan menghancurkan informasi ini juga.
Dalam kasus tertentu, Anda mungkin ingin membungkus semua pengecualian dalam objek pengecualian khusus, sehingga Anda dapat memberikan informasi tambahan tentang apa yang dilakukan kode ketika pengecualian dilemparkan.
Untuk melakukan ini, tentukan kelas baru yang mewarisi Exception, tambahkan keempat konstruktor pengecualian , dan opsional konstruktor tambahan yang mengambil InnerExceptionserta informasi tambahan, dan lempar kelas pengecualian baru Anda, yang lulus exsebagai InnerExceptionparameter . Dengan melewati yang asliInnerException , Anda menyimpan semua properti pengecualian asli, termasuk jejak tumpukan.
throw new MyCustomException(myMessage, ex);tentu saja.
ex.Message, ini lebih buruk.
[Serializable()].
throw;nomor baris aktual tempat pengecualian terjadi diganti dengan nomor baris throw;. Bagaimana Anda menyarankan penanganan itu? stackoverflow.com/questions/2493779/...
Yang pertama mempertahankan stacktrace asli:
try { ... }
catch
{
// Do something.
throw;
}
Yang kedua memungkinkan Anda untuk mengubah jenis pengecualian dan / atau pesan dan data lainnya:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
Ada juga cara ketiga di mana Anda melewati pengecualian batin:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
Saya akan merekomendasikan menggunakan:
Satu hal lain yang saya tidak melihat ada yang membuat:
Jika Anda tidak melakukan apa pun di blok {} catch Anda, mencoba ... catch tidak ada gunanya. Saya melihat ini setiap waktu:
try
{
//Code here
}
catch
{
throw;
}
Atau lebih buruk:
try
{
//Code here
}
catch(Exception ex)
{
throw ex;
}
Terburuk belum:
try
{
//Code here
}
catch(Exception ex)
{
throw new System.Exception(ex.Message);
}
throw melemparkan kembali pengecualian yang tertangkap, mempertahankan jejak tumpukan, sementara throw new Exception kehilangan beberapa detail pengecualian yang tertangkap.
Anda biasanya akan menggunakan throw sendiri untuk mencatat pengecualian tanpa sepenuhnya menanganinya pada saat itu.
BlackWasp memiliki artikel bagus yang cukup berjudul Melontar Pengecualian dalam C # .
Membuang Exception baru akan menghapus jejak stack saat ini.
throw;akan mempertahankan jejak tumpukan asli dan hampir selalu lebih bermanfaat. Pengecualian untuk aturan itu adalah ketika Anda ingin membungkus Pengecualian dalam pengecualian Anda sendiri. Anda kemudian harus melakukan:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
throwadalah untuk rethrowing pengecualian yang tertangkap. Ini bisa berguna jika Anda ingin melakukan sesuatu dengan pengecualian sebelum melewatkannya di rantai panggilan.
Menggunakan throwtanpa argumen mempertahankan tumpukan panggilan untuk tujuan debugging.
Contoh kedua Anda akan mengatur ulang jejak tumpukan pengecualian. Yang pertama paling akurat mempertahankan asal-usul pengecualian. Anda juga telah membuka bungkusan jenis asli yang merupakan kunci untuk mengetahui apa yang sebenarnya salah ... Jika yang kedua diperlukan untuk fungsionalitas - mis. Untuk menambahkan info tambahan atau membungkus ulang dengan jenis khusus seperti kustom 'HandleableException' maka hanya perlu Pastikan properti InnerException diatur juga!
Perbedaan terpenting adalah bahwa ekspresi kedua menghapus jenis pengecualian. Dan tipe pengecualian memainkan peran penting dalam menangkap pengecualian:
public void MyMethod ()
{
// both can throw IOException
try { foo(); } catch { throw; }
try { bar(); } catch(E) {throw new Exception(E.message); }
}
(...)
try {
MyMethod ();
} catch (IOException ex) {
Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
Console.WriteLine ("Other error"); // [2]
}
Jika foo()melempar IOException, [1]catch block akan menangkap exception. Tetapi ketika bar()melempar IOException, itu akan dikonversi menjadi Exceptionsemut biasa dan tidak akan ditangkap oleh [1]catch block.
melempar atau melempar mantan, keduanya digunakan untuk melempar atau mengolah kembali pengecualian, ketika Anda hanya cukup mencatat informasi kesalahan dan tidak ingin mengirim informasi kembali ke pemanggil Anda cukup mencatat kesalahan dalam tangkapan dan pergi. Tetapi jika Anda ingin mengirim beberapa informasi yang bermakna tentang pengecualian ke pemanggil yang Anda gunakan melempar atau melempar mantan. Sekarang perbedaan antara throw dan throw ex adalah throw membuang jejak stack dan informasi lainnya tetapi throw ex menciptakan objek pengecualian baru dan karenanya jejak stack asli hilang. Jadi kapan kita harus menggunakan melempar dan melempar e, Masih ada beberapa situasi di mana Anda mungkin ingin memikirkan kembali pengecualian seperti mengatur ulang informasi tumpukan panggilan. Misalnya, jika metode ini di perpustakaan dan Anda ingin menyembunyikan rincian perpustakaan dari kode panggilan, Anda tidak perlu ingin tumpukan panggilan untuk memasukkan informasi tentang metode pribadi dalam perpustakaan. Dalam hal itu, Anda bisa menangkap pengecualian dalam metode publik perpustakaan dan kemudian rethrow sehingga tumpukan panggilan dimulai pada metode publik tersebut.
Tidak ada jawaban di sini yang menunjukkan perbedaan, yang dapat membantu orang yang berjuang untuk memahami perbedaannya. Pertimbangkan kode contoh ini:
using System;
using System.Collections.Generic;
namespace ExceptionDemo
{
class Program
{
static void Main(string[] args)
{
void fail()
{
(null as string).Trim();
}
void bareThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw;
}
}
void rethrow()
{
try
{
fail();
}
catch (Exception e)
{
throw e;
}
}
void innerThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw new Exception("outer", e);
}
}
var cases = new Dictionary<string, Action>()
{
{ "Bare Throw:", bareThrow },
{ "Rethrow", rethrow },
{ "Inner Throw", innerThrow }
};
foreach (var c in cases)
{
Console.WriteLine(c.Key);
Console.WriteLine(new string('-', 40));
try
{
c.Value();
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
Yang menghasilkan output berikut:
Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
--- End of inner exception stack trace ---
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Bare throw, seperti yang ditunjukkan dalam jawaban sebelumnya, dengan jelas menunjukkan baris kode asli yang gagal (baris 12) serta dua titik lain yang aktif dalam tumpukan panggilan ketika pengecualian terjadi (baris 19 dan 64).
Keluaran dari kasus lemparan ulang menunjukkan mengapa ini merupakan masalah. Ketika pengecualian diulang kembali seperti ini, pengecualian tidak akan menyertakan informasi tumpukan asli. Perhatikan bahwa hanyathrow e titik tumpukan panggilan (saluran 35) dan terluar (saluran 64) yang disertakan. Akan sulit untuk melacak metode gagal () sebagai sumber masalah jika Anda melempar pengecualian dengan cara ini.
Kasus terakhir (innerThrow) paling rumit dan mencakup lebih banyak informasi daripada yang di atas. Karena kami membuat instance pengecualian baru, kami mendapat kesempatan untuk menambahkan informasi kontekstual (pesan "luar", di sini tetapi kami juga dapat menambahkan ke kamus. Data pada pengecualian baru) serta menjaga semua informasi dalam aslinya pengecualian (termasuk tautan bantuan, kamus data, dll.).