coba / tangkap + gunakan, sintaks kanan

189

Yang mana:

using (var myObject = new MyClass())
{
   try
   {
      // something here...
   }
   catch(Exception ex)
   {
      // Handle exception
   }
}

ATAU

try
{
   using (var myObject = new MyClass())
   {
      // something here...
   }
}
catch(Exception ex)
{
   // Handle exception
}
Xaqron
sumber
7
Hanya sebuah catatan: seseorang harus berhati-hati untuk hanya menangkap pengecualian yang benar-benar dapat ditangani (diperbaiki), kecuali untuk penebangan, atau membungkusnya.
John Saunders
1
Harap diingat bahwa juga yang terakhir }dari usingpernyataan dapat membuang pengecualian sebagai diingatkan di sini .
Giulio Caccin
1
TIL bahwa debugger (dalam VS) tidak akan memanggil metode buang jika Anda menggunakan blok kode pertama. Karena pernyataan menggunakan itu sendiri dapat membuang pengecualian, itu membantu saya untuk menggunakan blok kedua untuk memastikan tersirat finallydisebut metode buang.
ShooShoSha

Jawaban:

98

Saya lebih suka yang kedua. Semoga juga menjebak kesalahan yang berkaitan dengan penciptaan objek juga.

Jonathan Wood
sumber
11
Saya tidak setuju dengan saran ini. Jika Anda mengharapkan pembuatan objek untuk membuat kesalahan, maka penanganan pengecualian itu harus keluar. Jika ada beberapa pertanyaan tentang ke mana penanganan harus pergi, maka pengecualian yang diharapkan harus menjadi sesuatu yang lain — kecuali jika Anda menganjurkan menangkap pengecualian acak yang mungkin atau mungkin tidak diantisipasi, yang merupakan pola anti-klasik (di luar memproses atau Handler Exception Handler thread).
Jeffrey L Whitledge
1
@ Jeffrey: Pendekatan yang saya jelaskan telah membantu saya dengan baik dan saya sudah melakukan ini sejak lama. Tidak ada yang mengatakan apa-apa tentang mengharapkan penciptaan objek gagal. Tetapi dengan membungkus operasi yang berpotensi gagal dalam tryblok, yang memungkinkan Anda untuk memunculkan pesan kesalahan jika ada yang gagal, program sekarang memiliki kemampuan untuk memulihkan dan memberi tahu pengguna.
Jonathan Wood
Jawaban Anda sudah benar, tetapi terus saran bahwa mencoba / menangkap memiliki untuk berada di sana (segera) setiap saat.
Henk Holterman
17
Saya pikir yang pertama memiliki kelebihan juga, pertimbangkan transaksi DB using( DBConnection conn = DBFactory.getConnection())yang perlu dibatalkan jika ada pengecualian. Menurut saya keduanya memiliki tempat masing-masing.
wfoster
1
Itu juga akan menjebak kesalahan terkait dengan pembuangan objek.
Ahmad Ibrahim
39

Karena blok menggunakan hanyalah penyederhanaan sintaks dari coba / akhirnya ( MSDN ), secara pribadi saya akan mengikuti yang berikut, meskipun saya ragu itu sangat berbeda dari opsi kedua Anda:

MyClass myObject = null;
try {
  myObject = new MyClass();
  //important stuff
} catch (Exception ex) {
  //handle exception
} finally {
  if(myObject is IDisposable) myObject.Dispose();
}
chezy525
sumber
4
Menurut Anda mengapa menambahkan finallyblok lebih disukai daripada usingpernyataan itu?
Cody Grey
10
Menambahkan finallyblok yang membuang objek IDisposable adalah apa yang usingdilakukan pernyataan. Secara pribadi, saya suka ini daripada usingblok tertanam karena saya pikir ini lebih bersih menyatakan di mana semuanya terjadi, dan itu semua pada "level" yang sama. Saya juga suka ini lebih dari beberapa usingblok tertanam ... tapi itu semua hanya preferensi saya.
chezy525
8
Jika Anda menerapkan banyak penanganan pengecualian, Anda harus benar-benar menikmati mengetik! Kata kunci "menggunakan" itu telah ada sejak lama dan artinya cukup jelas bagi saya. Dan menggunakannya membantu membuat sisa kode saya lebih jelas dengan menjaga jumlah kekacauan minimum.
Jonathan Wood
2
Ini salah. Objek harus dipakai di luar trypernyataan untuk dibuang di dalam finallypernyataan; jika tidak, itu akan menimbulkan kesalahan kompiler: "Penggunaan variabel lokal yang belum
ditentukan
3
Secara teknis, itu juga tidak bisa dikompilasi. Cannot assign null to implicitly-typed local variable;) Tapi saya tahu apa yang Anda maksud dan secara pribadi lebih suka ini daripada menggunakan blok pakai.
Connell
20

Tergantung. Jika Anda menggunakan Windows Communication Foundation (WCF), using(...) { try... }tidak akan berfungsi dengan benar jika proksi dalam usingpernyataan berada dalam keadaan pengecualian, yaitu Membuang proksi ini akan menyebabkan pengecualian lain.

Secara pribadi, saya percaya pada pendekatan penanganan minimal, yaitu hanya menangani pengecualian yang Anda sadari pada titik eksekusi. Dengan kata lain, jika Anda tahu bahwa inisialisasi variabel dalam usingdapat membuang pengecualian tertentu, saya membungkusnya dengan try-catch. Demikian pula, jika di dalam usingtubuh sesuatu terjadi, yang tidak terkait langsung dengan variabel using, maka saya membungkusnya dengan yang lain tryuntuk pengecualian khusus itu. Saya jarang menggunakan Exceptiondi saya catches.

Tapi saya suka IDisposabledan usingmungkin saya bias.

Schultz9999
sumber
19

Jika pernyataan tangkap Anda perlu mengakses variabel yang dideklarasikan dalam pernyataan menggunakan, maka di dalam adalah satu-satunya pilihan Anda.

Jika pernyataan tangkapan Anda membutuhkan objek yang direferensikan dalam penggunaan sebelum dibuang, maka di dalam adalah satu-satunya pilihan Anda.

Jika pernyataan tangkapan Anda mengambil tindakan berdurasi tidak diketahui, seperti menampilkan pesan kepada pengguna, dan Anda ingin membuang sumber daya Anda sebelum itu terjadi, maka di luar adalah pilihan terbaik Anda.

Setiap kali saya memiliki scenerio yang mirip dengan ini, blok try-catch biasanya dalam metode yang berbeda lebih jauh dari tumpukan panggilan dari menggunakan. Itu tidak khas untuk metode untuk mengetahui bagaimana menangani pengecualian yang terjadi di dalamnya seperti ini.

Jadi rekomendasi umum saya ada di luar — jauh di luar.

private void saveButton_Click(object sender, EventArgs args)
{
    try
    {
        SaveFile(myFile); // The using statement will appear somewhere in here.
    }
    catch (IOException ex)
    {
        MessageBox.Show(ex.Message);
    }
}
Jeffrey L Whitledge
sumber
10

Keduanya adalah sintaks yang valid. Ini benar-benar tergantung pada apa yang ingin Anda lakukan: jika Anda ingin menangkap kesalahan terkait dengan membuat / membuang objek, gunakan yang kedua. Jika tidak, gunakan dulu.

Menghancurkan
sumber
8

Ada satu hal penting yang akan saya panggil di sini: Yang pertama tidak akan menangkap pengecualian yang muncul karena memanggil MyClasskonstruktor.

Madhur Ahuja
sumber
3

Dari C # 8.0, saya lebih suka menggunakan yang kedua sama seperti ini

public class Person : IDisposable
{
    public Person()
    {
        int a = 0;
        int b = Id / a;
    }
    public int Id { get; set; }

    public void Dispose()
    {
    }
}

lalu

static void Main(string[] args)
    {

        try
        {
            using var person = new Person();
        }
        catch (Exception ex) when
        (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
        ex.TargetSite.MemberType == System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Constructor Person");
        }
        catch (Exception ex) when
       (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
       ex.TargetSite.MemberType != System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Person");
        }
        catch (Exception ex)
        {
            Debug.Write(ex.Message);
        }
        finally
        {
            Debug.Write("finally");
        }
    }
Reza Jenabi
sumber
1

Jika objek yang Anda inisialisasi di blok Using () mungkin melempar pengecualian apa pun, maka Anda harus memilih sintaks kedua jika tidak keduanya sama-sama valid.

Dalam skenario saya, saya harus membuka file dan saya melewati filePath di konstruktor objek yang saya inisialisasi di blok Using () dan mungkin membuang pengecualian jika filePath salah / kosong. Jadi dalam hal ini, sintaks kedua masuk akal.

Kode sampel saya: -

try
{
    using (var obj= new MyClass("fileName.extension"))
    {

    }
}
catch(Exception ex)
{
     //Take actions according to the exception.
}
Ankur Arora
sumber
1

Dari C # 8.0 pada , Anda dapat menyederhanakan usingpernyataan di bawah beberapa kondisi untuk menyingkirkan blok bersarang, dan kemudian hanya berlaku untuk blok terlampir.

Jadi dua contoh Anda dapat direduksi menjadi:

using var myObject = new MyClass();
try
{
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

Dan:

try
{
   using var myObject = new MyClass();
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

Keduanya cukup jelas; dan kemudian itu mengurangi pilihan antara keduanya menjadi masalah apa yang Anda inginkan ruang lingkup objek menjadi, di mana Anda ingin menangani kesalahan instantiation, dan ketika Anda ingin membuangnya.

Jason C
sumber