Apa kegunaan "menggunakan" di C #?

319

Pengguna kokos menjawab Fitur Tersembunyi yang indah dari pertanyaan C # dengan menyebutkan usingkata kunci. Dapatkah Anda menguraikan itu? Apa kegunaan dari using?

ubermonkey
sumber
Ini adalah cara C # untuk mendukung idiom RAII: hackcraft.net/raii
Nemanja Trifunovic
1
Anda dapat menggunakan objek yang telah mengimplementasikan antarmuka IDispose. Menggunakan akan memanggil metode Buang ketika objek itu keluar dari ruang lingkup. Ini menjamin untuk memanggil Buang meskipun ada pengecualian. Ini berfungsi seperti akhirnya klausa dan jalankan Buang.
CharithJ

Jawaban:

480

Alasan untuk usingpernyataan ini adalah untuk memastikan bahwa objek dibuang segera setelah keluar dari ruang lingkup, dan itu tidak memerlukan kode eksplisit untuk memastikan bahwa ini terjadi.

Seperti dalam Memahami pernyataan 'using' di C # (codeproject) dan Menggunakan objek yang mengimplementasikan IDisposable (microsoft) , kompiler C # mengkonversi

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();
}

untuk

{ // Limits scope of myRes
    MyResource myRes= new MyResource();
    try
    {
        myRes.DoSomething();
    }
    finally
    {
        // Check for a null resource.
        if (myRes != null)
            // Call the object's Dispose method.
            ((IDisposable)myRes).Dispose();
    }
}

C # 8 memperkenalkan sintaks baru, bernama " using declarations ":

Deklarasi menggunakan adalah deklarasi variabel yang didahului dengan menggunakan kata kunci. Ini memberitahu kompiler bahwa variabel yang dideklarasikan harus dibuang di akhir lingkup melampirkan.

Jadi kode yang setara di atas adalah:

using var myRes = new MyResource();
myRes.DoSomething();

Dan ketika kontrol meninggalkan ruang lingkup yang berisi (biasanya metode, tetapi juga bisa menjadi blok kode), myResakan dibuang.

paulwhit
sumber
129
Perhatikan bahwa itu tidak selalu soal benda yang dibuang dengan benar , tetapi lebih pada apakah benda itu dibuang tepat waktu. Objek yang menerapkan IDisposable yang berpegang pada sumber daya yang tidak dikelola seperti stream dan file handle juga akan menerapkan finalizer yang akan memastikan bahwa Buang dipanggil saat pengumpulan sampah. Masalahnya adalah bahwa GC mungkin tidak terjadi untuk waktu yang relatif lama. usingMemastikan itu Disposedipanggil setelah Anda selesai dengan objek.
John Saunders
1
Harap dicatat bahwa kode yang dihasilkan sedikit berbeda ketika MyRessourcesebuah struct. Jelas tidak ada tes untuk nullity, tetapi juga tidak ada tinju IDisposable. Panggilan virtual terkendali dipancarkan.
Romain Verdier
4
Mengapa tidak ada yang menyebutkan bahwa menggunakan juga digunakan untuk mengimpor ruang nama?
Kyle Delaney
3
Perhatikan bahwa jika Anda langsung menulis kode versi kedua, hasilnya tidak sama. Jika Anda menggunakan using, variabel yang dibangun di dalamnya dibaca hanya. Tidak ada cara untuk mencapai ini untuk variabel lokal tanpa usingpernyataan.
Massimiliano Kraus
1
@ JohnSaunders Selain itu, finalizer tidak dijamin akan dipanggil.
Pablo H
124

Karena banyak orang masih melakukan:

using (System.IO.StreamReader r = new System.IO.StreamReader(""))
using (System.IO.StreamReader r2 = new System.IO.StreamReader("")) {
   //code
}

Saya kira banyak orang masih tidak tahu yang dapat Anda lakukan:

using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
   //code
}
BlackTigerX
sumber
2
Apakah mungkin untuk menggunakan beberapa objek dari jenis yang berbeda dalam satu pernyataan menggunakan?
Agnel Kurian
12
@AgnelKurian No: "error CS1044: Tidak dapat menggunakan lebih dari satu jenis dalam untuk, menggunakan, memperbaiki, atau pernyataan deklarasi"
David Sykes
10
Bagaimana ini menjawab pertanyaan?
Liam
Sebenarnya saya tidak tahu saya bisa menulis dua menggunakan statemens sebelum satu blok kode (akan membuat sarang mereka setiap waktu).
kub1x
97

Hal-hal seperti ini:

using (var conn = new SqlConnection("connection string"))
{
   conn.Open();

    // Execute SQL statement here on the connection you created
}

Ini SqlConnectionakan ditutup tanpa perlu memanggil .Close()fungsi secara eksplisit , dan ini akan terjadi bahkan jika pengecualian dilemparkan , tanpa perlu a try/ catch/ finally.

Joel Coehoorn
sumber
1
bagaimana jika saya menggunakan "menggunakan" di dalam metode, dan saya kembali di tengah menggunakan. Apakah ada masalah?
francisco_ssb
1
Tidak ada masalah. Dalam contoh di sini, koneksi masih akan ditutup, bahkan jika Anda returndari tengah usingblok.
Joel Coehoorn
30

menggunakan dapat digunakan untuk memanggil IDisposable. Itu juga bisa digunakan untuk tipe alias.

using (SqlConnection cnn = new SqlConnection()) { /*code*/}
using f1 = System.Windows.Forms.Form;
MagicKat
sumber
21

menggunakan, dalam arti

using (var foo = new Bar())
{
  Baz();
}

Sebenarnya singkatan untuk mencoba / akhirnya memblokir. Itu sama dengan kode:

var foo = new Bar();
try
{
  Baz();
}
finally
{
  foo.Dispose();
}

Anda tentu akan memperhatikan bahwa cuplikan pertama jauh lebih ringkas daripada yang kedua dan juga ada banyak hal yang mungkin ingin Anda lakukan sebagai pembersihan meskipun pengecualian dilemparkan. Karena itu, kami membuat kelas yang kami sebut Lingkup yang memungkinkan Anda untuk mengeksekusi kode arbitrer dalam metode Buang. Jadi, misalnya, jika Anda memiliki properti bernama IsWorking yang Anda selalu ingin setel ke false setelah mencoba melakukan operasi, Anda akan melakukannya seperti ini:

using (new Scope(() => IsWorking = false))
{
  IsWorking = true;
  MundaneYetDangerousWork();
}

Anda dapat membaca lebih lanjut tentang solusi kami dan bagaimana kami mendapatkannya di sini .

David Mitchell
sumber
12

Dokumentasi Microsoft menyatakan bahwa menggunakan memiliki fungsi ganda ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ), baik sebagai arahan dan dalam pernyataan . Sebagai pernyataan , seperti yang ditunjukkan di sini di jawaban lain, kata kunci pada dasarnya adalah sintaksis gula untuk menentukan ruang lingkup untuk membuang objek IDisposable . Sebagai arahan , ini secara rutin digunakan untuk mengimpor ruang nama dan tipe. Juga sebagai arahan, Anda dapat membuat alias untuk ruang nama dan jenis, seperti yang ditunjukkan dalam buku "C # 5.0 In a Nutshell: The Definitive Guide" ( http://www.amazon.com/5-0-Nutshell-The- Definitive-Reference-ebook / dp / B008E6I1K8), oleh Joseph dan Ben Albahari. Satu contoh:

namespace HelloWorld
{
    using AppFunc = Func<IDictionary<DateTime, string>, List<string>>;
    public class Startup
    {
        public static AppFunc OrderEvents() 
        {
            AppFunc appFunc = (IDictionary<DateTime, string> events) =>
            {
                if ((events != null) && (events.Count > 0))
                {
                    List<string> result = events.OrderBy(ev => ev.Key)
                        .Select(ev => ev.Value)
                        .ToList();
                    return result;
                }
                throw new ArgumentException("Event dictionary is null or empty.");
            };
            return appFunc;
        }
    }
}

Ini adalah sesuatu untuk diadopsi dengan bijak, karena penyalahgunaan praktik ini dapat merusak kejelasan kode seseorang. Ada penjelasan yang bagus tentang alias C #, juga menyebutkan pro dan kontra, di DotNetPearls ( http://www.dotnetperls.com/using-alias ).

Aureliano Buendia
sumber
4
Tidak akan bohong: Saya benci penggunaan usingsebagai alat alias. Itu membingungkan saya ketika membaca kode - saya sudah tahu yang System.Collectionsada dan memiliki IEnumerable<T>kelas. Menggunakan alias untuk menyebutnya sesuatu yang lain mengaburkannya untuk saya. Saya melihat using FooCollection = IEnumerable<Foo>sebagai cara untuk membuat pengembang kemudian membaca kode dan berpikir, "Apa itu FooCollectiondan mengapa tidak ada kelas untuk itu di suatu tempat?" Saya tidak pernah menggunakannya dan akan mencegah penggunaannya. Tapi itu mungkin hanya aku.
Ari Roth
1
Tambahan: Saya akan mengakui bahwa mungkin ada gunanya untuk itu sesekali, seperti dalam contoh Anda di mana Anda menggunakannya untuk menentukan delegasi. Tapi saya berpendapat itu relatif jarang.
Ari Roth
10

Saya sudah banyak menggunakannya di masa lalu untuk bekerja dengan input dan output stream. Anda dapat membuat sarang dengan baik dan menghilangkan banyak potensi masalah yang biasanya Anda alami (dengan secara otomatis menelepon buang). Sebagai contoh:

        using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
        {
            using (BufferedStream bs = new BufferedStream(fs))
            {
                using (System.IO.StreamReader sr = new StreamReader(bs))
                {
                    string output = sr.ReadToEnd();
                }
            }
        }
Sam Schutte
sumber
8

Hanya menambahkan sedikit sesuatu yang saya terkejut tidak muncul. Fitur yang paling menarik dari menggunakan (menurut saya) adalah bahwa tidak peduli bagaimana Anda keluar dari blok menggunakan, ia akan selalu membuang objek. Ini termasuk pengembalian dan pengecualian.

using (var db = new DbContext())
{
    if(db.State == State.Closed) throw new Exception("Database connection is closed.");
    return db.Something.ToList();
}

Tidak masalah jika pengecualian dilemparkan atau daftar dikembalikan. Objek DbContext akan selalu dibuang.

Pluc
sumber
6

Penggunaan besar lainnya dari penggunaan adalah ketika memulai dialog modal.

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using
Lucas
sumber
1
Apakah maksud Anda frm.ShowDialog?
UuDdLrLrSs
5

Kesimpulannya, ketika Anda menggunakan variabel lokal dari tipe yang mengimplementasikan IDisposable, selalu , tanpa kecuali, gunakan using1 .

Jika Anda menggunakan IDisposablevariabel nonlokal , maka selalu terapkan IDisposablepola tersebut .

Dua aturan sederhana, tidak terkecuali 1 . Mencegah kebocoran sumber daya sebaliknya adalah rasa sakit yang nyata di * ss.


1) : Satu-satunya pengecualian adalah - saat Anda menangani pengecualian. Maka mungkin lebih sedikit kode untuk memanggil Disposesecara eksplisit di finallyblok.

Konrad Rudolph
sumber
5

Anda dapat menggunakan alias namespace dengan contoh berikut:

using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;

Ini disebut menggunakan directive alias seperti yang Anda lihat, itu dapat digunakan untuk menyembunyikan referensi bertele-tele jika Anda ingin membuatnya jelas dalam kode Anda apa yang Anda rujuk misalnya

LegacyEntities.Account

dari pada

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

atau sederhana

Account   // It is not obvious this is a legacy entity
VictorySaber
sumber
4

Menariknya, Anda juga dapat menggunakan pola using / IDisposable untuk hal-hal menarik lainnya (seperti titik lain cara Rhino Mocks menggunakannya). Pada dasarnya, Anda dapat memanfaatkan fakta bahwa kompiler akan selalu memanggil .Dosisikan pada objek "bekas". Jika Anda memiliki sesuatu yang perlu terjadi setelah operasi tertentu ... sesuatu yang memiliki awal dan akhir yang pasti ... maka Anda bisa membuat kelas IDisposable yang memulai operasi di konstruktor, dan selesai di metode Buang.

Ini memungkinkan Anda untuk menggunakan sintaks penggunaan yang benar-benar bagus untuk menunjukkan awal dan akhir operasi yang eksplisit tersebut. Ini juga cara kerja System.Transactions.

Joel Martinez
sumber
3

Saat menggunakan ADO.NET Anda dapat menggunakan keywork untuk hal-hal seperti objek koneksi Anda atau objek pembaca. Dengan begitu ketika blok kode selesai akan secara otomatis membuang koneksi Anda.

Joseph Daigle
sumber
2
Saya hanya akan menambahkan bahwa blok kode bahkan tidak harus selesai. Blok penggunaan akan membuang sumber daya bahkan jika terjadi pengecualian yang tidak tertangani.
harpo
Untuk memperjelas lebih lanjut, ini adalah cara untuk memastikan Pengumpul Sampah menjaga alokasi Anda saat Anda menginginkannya, alih-alih melakukannya kapan pun Anda mau.
moswald
3
public class ClassA:IDisposable

{
   #region IDisposable Members        
    public void Dispose()
    {            
        GC.SuppressFinalize(this);
    }
    #endregion
}

public void fn_Data()

    {
     using (ClassA ObjectName = new ClassA())
            {
                //use objectName 
            }
    }
Shiraj Momin
sumber
2

menggunakan digunakan ketika Anda memiliki sumber daya yang ingin Anda buang setelah digunakan.

Misalnya jika Anda mengalokasikan sumber daya File dan hanya perlu menggunakannya dalam satu bagian kode untuk sedikit membaca atau menulis, menggunakan sangat membantu untuk membuang sumber daya File segera setelah Anda selesai.

Sumber daya yang digunakan perlu menerapkan IDisposable agar berfungsi dengan benar.

Contoh:

using (File file = new File (parameters))
{
    *code to do stuff with the file*
}
Bob Wintemberg
sumber
1

Kata kunci yang menggunakan mendefinisikan lingkup untuk objek dan kemudian membuang objek ketika cakupan selesai. Sebagai contoh.

using (Font font2 = new Font("Arial", 10.0f))
{
    // use font2
}

Lihat di sini untuk artikel MSDN di C # menggunakan kata kunci.

David Basarab
sumber
1

Bukan berarti itu sangat penting, tetapi menggunakan juga dapat digunakan untuk mengubah sumber daya dengan cepat. Ya sekali pakai seperti yang disebutkan sebelumnya, tetapi mungkin secara khusus Anda tidak ingin sumber daya mereka tidak cocok dengan sumber daya lainnya selama sisa eksekusi Anda. Jadi, Anda ingin membuangnya agar tidak mengganggu di tempat lain.


sumber
1

Berkat komentar di bawah ini, saya akan membersihkan posting ini sedikit (saya seharusnya tidak menggunakan kata-kata 'pengumpulan sampah' pada saat itu, permintaan maaf):
Ketika Anda menggunakan, itu akan memanggil metode Buang () pada objek pada akhir lingkup penggunaan. Jadi Anda dapat memiliki sedikit kode pembersihan yang bagus dalam metode Buang () Anda.
Poin-poin di sini yang diharapkan akan menghapus tanda-tanda ini: Jika Anda menerapkan IDisposable, pastikan Anda menghubungi GC.SuppressFinalize () dalam implementasi Buang () Anda, karena jika tidak, pengumpulan sampah otomatis akan mencoba untuk ikut serta dan menyelesaikannya di beberapa titik, yang setidaknya akan membuang-buang sumber daya jika Anda sudah Buang () d dari itu.

Nenek
sumber
Ini memiliki efek tidak langsung. Karena Anda telah membuang objek secara eksplisit, objek tersebut tidak memerlukan finalisasi dan karena itu dapat menjadi GC sebelumnya.
Kent Boogaart
1

Contoh lain dari penggunaan yang wajar di mana objek tersebut segera dibuang:

using (IDataReader myReader = DataFunctions.ExecuteReader(CommandType.Text, sql.ToString(), dp.Parameters, myConnectionString)) 
{
    while (myReader.Read()) 
    {
        MyObject theObject = new MyObject();
        theObject.PublicProperty = myReader.GetString(0);
        myCollection.Add(theObject);
    }
}
Brendan Kendrick
sumber
1

Segala sesuatu di luar kurung keriting dibuang, jadi itu bagus untuk membuang benda Anda jika Anda tidak menggunakannya. Ini karena jika Anda memiliki objek SqlDataAdapter dan Anda menggunakannya hanya sekali dalam siklus hidup aplikasi dan Anda hanya mengisi satu dataset dan Anda tidak membutuhkannya lagi, Anda dapat menggunakan kode:

using(SqlDataAdapter adapter_object = new SqlDataAdapter(sql_command_parameter))
{
   // do stuff
} // here adapter_object is disposed automatically
milot
sumber
1

Pernyataan menggunakan menyediakan mekanisme kenyamanan untuk menggunakan objek IDisposable dengan benar. Sebagai aturan, ketika Anda menggunakan objek IDisposable, Anda harus mendeklarasikan dan membuat instance dalam pernyataan menggunakan. Pernyataan menggunakan memanggil metode Buang pada objek dengan cara yang benar, dan (ketika Anda menggunakannya seperti yang ditunjukkan sebelumnya) itu juga menyebabkan objek itu sendiri keluar dari ruang lingkup begitu Buang disebut. Di dalam blok menggunakan, objek hanya-baca dan tidak dapat dimodifikasi atau dipindahkan.

Ini berasal dari: sini

Snowell
sumber
1

Bagi saya nama "using" sedikit membingungkan, karena ini bisa menjadi arahan untuk mengimpor Namespace atau pernyataan (seperti yang dibahas di sini) untuk penanganan kesalahan.

Nama yang berbeda untuk penanganan kesalahan pasti menyenangkan, dan mungkin yang lebih jelas.

Seb
sumber
1

Ini juga dapat digunakan untuk membuat cakupan untuk Contoh:

class LoggerScope:IDisposable {
   static ThreadLocal<LoggerScope> threadScope = 
        new ThreadLocal<LoggerScope>();
   private LoggerScope previous;

   public static LoggerScope Current=> threadScope.Value;

   public bool WithTime{get;}

   public LoggerScope(bool withTime){
       previous = threadScope.Value;
       threadScope.Value = this;
       WithTime=withTime;
   }

   public void Dispose(){
       threadScope.Value = previous;
   }
}


class Program {
   public static void Main(params string[] args){
       new Program().Run();
   }

   public void Run(){
      log("something happend!");
      using(new LoggerScope(false)){
          log("the quick brown fox jumps over the lazy dog!");
          using(new LoggerScope(true)){
              log("nested scope!");
          }
      }
   }

   void log(string message){
      if(LoggerScope.Current!=null){
          Console.WriteLine(message);
          if(LoggerScope.Current.WithTime){
             Console.WriteLine(DateTime.Now);
          }
      }
   }

}
Siamand
sumber
1

Pernyataan menggunakan memberitahu .NET untuk melepaskan objek yang ditentukan dalam blok menggunakan setelah tidak lagi diperlukan. Jadi, Anda harus menggunakan blok 'using' untuk kelas yang membutuhkan pembersihan setelah mereka, seperti Jenis System.IO.

deepak samantaray
sumber
1

Ada dua penggunaan usingkata kunci dalam C # sebagai berikut.

  1. Sebagai arahan

    Secara umum kami menggunakan using kata kunci untuk menambahkan ruang nama dalam kode di belakang dan file kelas. Kemudian tersedia semua kelas, antarmuka, dan kelas abstrak serta metode dan propertinya di halaman saat ini.

    Contoh:

    using System.IO;
  2. Sebagai pernyataan

    Ini adalah cara lain untuk menggunakan using kata kunci dalam C #. Ini memainkan peran penting dalam meningkatkan kinerja dalam Pengumpulan Sampah.

    Itu using Memastikan pernyataan bahwa Buang () disebut bahkan jika pengecualian terjadi ketika Anda membuat objek dan memanggil metode, properti dan sebagainya. Buang () adalah metode yang ada di antarmuka IDisposable yang membantu menerapkan Pengumpulan Sampah kustom. Dengan kata lain jika saya melakukan beberapa operasi basis data (Sisipkan, Perbarui, Hapus) tetapi entah bagaimana pengecualian terjadi maka di sini pernyataan menggunakan menutup koneksi secara otomatis. Tidak perlu memanggil metode koneksi Tutup () secara eksplisit.

    Faktor penting lainnya adalah membantu dalam Connection Pooling. Koneksi Pooling di .NET membantu menghilangkan penutupan koneksi database beberapa kali. Ini mengirimkan objek koneksi ke kolam untuk digunakan di masa depan (panggilan database berikutnya). Lain kali koneksi database dipanggil dari aplikasi Anda pool koneksi mengambil objek yang tersedia di pool. Sehingga sangat membantu untuk meningkatkan kinerja aplikasi. Jadi ketika kita menggunakan statemen using the controller mengirimkan objek ke pool koneksi secara otomatis, tidak perlu memanggil metode Close () dan Dispose () secara eksplisit.

    Anda dapat melakukan hal yang sama seperti apa yang dilakukan pernyataan menggunakan dengan menggunakan blok coba-tangkap dan panggil Buang () di dalam blok akhirnya secara eksplisit. Tetapi pernyataan menggunakan melakukan panggilan secara otomatis untuk membuat kode lebih bersih dan lebih elegan. Di dalam blok menggunakan, objek hanya-baca dan tidak dapat dimodifikasi atau dipindahkan.

    Contoh:

    string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
    
    using (SqlConnection conn = new SqlConnection(connString))
    {
          SqlCommand cmd = conn.CreateCommand();
          cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
          conn.Open();
          using (SqlDataReader dr = cmd.ExecuteReader())
          {
             while (dr.Read())
             Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));
          }
    }

Dalam kode sebelumnya saya tidak menutup koneksi apa pun; itu akan menutup secara otomatis. The usingpernyataan akan memanggil conn.close () secara otomatis karena usingpernyataan ( using (SqlConnection conn = new SqlConnection(connString)) dan sama untuk objek SqlDataReader. Dan juga jika ada pengecualian itu akan menutup koneksi secara otomatis.

Untuk informasi lebih lanjut, lihat Penggunaan dan Pentingnya Menggunakan di C # .

Chamila Maddumage
sumber
-1

menggunakan sebagai pernyataan secara otomatis memanggil buang pada objek yang ditentukan. Objek harus mengimplementasikan antarmuka IDisposable. Dimungkinkan untuk menggunakan beberapa objek dalam satu pernyataan selama mereka dari tipe yang sama.

CLR mengubah kode Anda menjadi MSIL. Dan statemen penggunaan diterjemahkan menjadi blok percobaan dan akhirnya. Ini adalah bagaimana pernyataan penggunaan diwakili dalam IL. Pernyataan menggunakan diterjemahkan menjadi tiga bagian: akuisisi, penggunaan, dan pembuangan. Sumber daya pertama kali diperoleh, kemudian penggunaannya dilampirkan dalam pernyataan coba dengan klausa akhirnya. Objek kemudian dibuang di klausa akhirnya.

Vazgen Torosyan
sumber
-3

Menggunakan Klausa digunakan untuk menentukan ruang lingkup untuk variabel tertentu. Sebagai contoh:

     Using(SqlConnection conn=new SqlConnection(ConnectionString)
            {
                Conn.Open()
            // Execute sql statements here.
           // You do not have to close the connection explicitly here as "USING" will close the connection once the object Conn becomes out of the defined scope.
            }
Riya Patil
sumber
Ini bisa menyesatkan seseorang, menggunakan adalah untuk membuang benda. Mungkin Anda membingungkan ini dengan blok kode, jika Anda ingin membatasi ruang lingkup variabel Anda dapat menggunakan blok kode bersarang untuk itu: public static void Main (string params [] args) {{// blok kode bersarang}}
luiseduardohd