C # "kullanarak" kullanımları nelerdir?


319

Kullanıcı kokos , C # sorusunun harika Gizli Özellikleriniusing anahtar kelimeden bahsederek yanıtladı . Bunu biraz açıklayabilir misin? Ne işe yarar using?


RAII deyimini desteklemenin bir C # yolu: hackcraft.net/raii
Nemanja Trifunovic

1
IDispose arabirimini uygulayan nesneler için kullanabilirsiniz. Bu nesne kapsam dışına çıktığında, kullanma Dispose yöntemini çağırır. Herhangi bir istisna olsa bile Dispose çağrılmasını garanti eder. Son olarak bir madde gibi çalışır ve Dispose işlemini yürütür.
CharithJ

Yanıtlar:


480

İfadenin nedeni using, nesnenin kapsam dışına çıkar çıkmaz atılmasını sağlamaktır ve bunun gerçekleşmesini sağlamak için açık kod gerektirmez.

Olduğu gibi C # (codeproject) 'de 'kullanarak' ifadesi anlama ve IDisposable (microsoft) uygulamak nesneleri kullanarak , C # derleyicisi dönüştürür

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

için

{ // 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, " bildirimleri kullanarak " adlı yeni bir sözdizimi sunar :

Kullanım bildirimi, önce using anahtar sözcüğünden önce gelen değişken bir bildirimdir. Derleyiciye bildirilen değişkenin kapalı alanın sonuna yerleştirilmesi gerektiğini söyler.

Yani yukarıdaki eşdeğer kod şöyle olacaktır:

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

Ve kontrol içeren kapsamı terk ettiğinde (genellikle bir yöntem, ancak aynı zamanda bir kod bloğu da olabilir), myResatılacaktır.


129
Bunun, nesnenin doğru bir şekilde atılmasının bir sorunu olmadığını, ancak zamanında atılmasının daha fazla olduğuna dikkat edin. Akışlar ve dosya tanıtıcıları gibi yönetilmeyen kaynaklara tutunan IDisposable uygulayan nesneler de, çöp toplama sırasında Dispose çağrılmasını sağlayacak bir sonlandırıcı uygular. Sorun şu ki GC nispeten uzun bir süre gerçekleşmeyebilir. nesneyi tamamladıktan sonra çağrıldığından usingemin olur Dispose.
John Saunders

1
MyRessourceBir yapı olduğunda oluşturulan kodun biraz farklı olduğunu lütfen unutmayın . Açıkçası hükümsüzlük testi yok, aynı zamanda boks yapmak da yok IDisposable. Kısıtlı bir sanal çağrı gönderilir.
Romain Verdier

4
Neden kimse kullanmanın isim alanlarını içe aktarmak için kullanıldığını söylemiyor?
Kyle Delaney

3
Doğrudan kodun ikinci sürümünü yazarsanız, sonucun aynı olmadığını unutmayın. Eğer kullanırsanız using, içine inşa değişken salt okunur. Yerel değişkenler için usingdeyim olmadan bunu başarmanın bir yolu yoktur .
Massimiliano Kraus

1
@JohnSaunders Ayrıca, sonlandırıcının çağrılması garanti edilmez.
Pablo H

124

Birçok insan hala yaptığı için:

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

Sanırım bir çok insan hala yapabileceğinizi bilmiyor:

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

2
Tek bir ifadede farklı türde birden fazla nesne kullanmak mümkün müdür?
Agnel Kurian

12
@AgnelKurian No: "hata CS1044: a, kullanma, sabit veya bildirim deyiminde birden fazla tür kullanılamıyor"
David Sykes

10
Bu soruya nasıl cevap veriyor?
Liam

Aslında tek bir kod bloğundan önce iki kullanarak statemens yazabilirsiniz bilmiyordum (her zaman onları yuva).
kub1x

97

Böyle şeyler:

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

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

Bu SqlConnection, .Close()işlevi açıkça çağırmaya gerek kalmadan kapatılacaktır ve bu, bir / / gereksinimi olmadan bir istisna atılmış olsa bile gerçekleşecektir .trycatchfinally


1
ne bir yöntem içinde "kullanma" kullanıyorsanız ve bir kullanım ortasında dönüyorum. Problem var mı?
francisco_ssb

1
Sorun değil. Buradaki örnekte return, usingbloğun ortasından olsanız bile bağlantı hala kapalı olacaktır .
Joel Coehoorn

30

kullanarak IDIposable çağrı yapmak için kullanılabilir. Diğer ad türlerinde de kullanılabilir.

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

21

kullanarak, anlamında

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

Aslında denemek için bir steno / nihayet blok. Bu koda eşdeğerdir:

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

Tabii ki, ilk snippet'in ikinciden çok daha özlü olduğunu ve ayrıca bir istisna atılmış olsa bile temizleme olarak yapmak isteyebileceğiniz birçok şey olduğunu not edeceksiniz. Bu nedenle, Dispose yönteminde rasgele kod çalıştırmanıza izin veren Scope olarak adlandırdığımız bir sınıf bulduk. Örneğin, bir işlemi gerçekleştirmeye çalıştıktan sonra her zaman false olarak ayarlamak istediğiniz IsWorking adlı bir özelliğiniz varsa, bunu şu şekilde yaparsınız:

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

Çözümümüz ve burada nasıl elde ettiğimiz hakkında daha fazla bilgi edinebilirsiniz .


12

Microsoft belgelerine durumları kullanarak bir çifte fonksiyonuna sahiptir ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx bir şekilde her ikisi), direktif ve ifadeleri . Bir açıklama olarak , burada diğer cevaplarda belirtildiği gibi, anahtar kelime, IDisposable bir nesneyi elden çıkarmak için bir kapsam belirlemek için sözdizimsel şekerdir . Bir yönerge olarak , ad alanlarını ve türlerini almak için rutin olarak kullanılır. Ayrıca yönerge olarak, oluşturabileceğiniz takma adları kitapta sivri out gibi, ad ve türleri için "Ceviz Kabuğundaki C # 5.0: Kesin Kılavuzu" ( http://www.amazon.com/5-0-Nutshell-The- Kesin-Referans-e-kitap / dp / B008E6I1K8), Joseph ve Ben Albahari. Bir örnek:

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;
        }
    }
}

Bu, akıllıca benimsenecek bir şeydir, çünkü bu uygulamanın kötüye kullanılması kişinin kodunun netliğine zarar verebilir. DotNetPearls'da ( http://www.dotnetperls.com/using-alias ) C # takma adlarıyla ilgili artıları ve eksileri de anlatan güzel bir açıklama var .


4
Yalan söylemeyeceğim: Takma ad aracı olarak kullanımından nefret ediyorumusing . Kodu okurken kafam karıştı - zaten System.Collectionsvar olduğunu ve IEnumerable<T>sınıfı olduğunu biliyorum . Başka bir ad vermek için bir takma ad kullanmak, onu benim için gizliyor. Daha using FooCollection = IEnumerable<Foo>sonra geliştiricilerin kodu okumasını ve "Cehennem nedir FooCollectionve neden bir yerde bunun için bir sınıf yok " diye düşünmesini sağlamanın bir yolu olarak görüyorum . Asla kullanmam ve kullanımını caydırırdım. Ama bu sadece ben olabilirim.
Ari Roth

1
Zeyilname: Temsilcinizi tanımlamak için kullandığınız örneğin örneğinde olduğu gibi, zaman zaman bunun bir kullanımının olabileceğini kabul edeceğim. Ama bunların nispeten nadir olduğunu iddia ediyorum.
Ari Roth

10

Geçmişte giriş ve çıkış akışlarıyla çalışmak için çok kullandım. Onları güzelce iç içe yerleştirebilirsiniz ve genellikle karşılaştığınız birçok potansiyel sorunu ortadan kaldırır (otomatik olarak imha çağrısı yaparak). Örneğin:

        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();
                }
            }
        }

8

Sadece şaşırdığım küçük bir şey eklemek gelmedi. Kullanmanın en ilginç özelliği (benim görüşüme göre), kullanım bloğundan nasıl çıkacağınızı bilmediğinizde, nesneyi her zaman atacaktır. Buna iadeler ve istisnalar dahildir.

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

Kural dışı durumun atılması veya listenin döndürülmesi önemli değildir. DbContext nesnesi her zaman atılır.


6

Kullanmanın bir başka harika kullanımı, kalıcı bir iletişim kutusu başlatılmasıdır.

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using

1
Şunu mu demek istedin frm.ShowDialog?
UuDdLrLrSs

5

Eğer bir türde bir yerel değişken kullandığınızda Sonuç olarak uygular o IDisposable, her zaman , istisnasız kullanmak using1 .

Eğer yerel olmayan kullanırsanız IDisposabledeğişkenleri, o zaman her zaman uygulamak IDisposabledeseni .

İki basit kural, istisna yok 1 . Aksi halde kaynak sızıntılarını önlemek * ss'de gerçek bir acıdır.


1) : Tek istisna - istisnaları ele alırken. Daha sonra blokta Disposeaçıkça çağırmak daha az kod olabilir finally.


5

Diğer ad ad alanını aşağıdaki örnekle kullanabilirsiniz:

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

Bu, gördüğünüz gibi bir takma ad yönergesi olarak adlandırılır , kodunuzda referansta bulunduğunuz şeyi açıkça belirtmek istiyorsanız uzun soluklu referansları gizlemek için kullanılabilir.

LegacyEntities.Account

onun yerine

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

ya da sadece

Account   // It is not obvious this is a legacy entity

4

İlginç bir şekilde, / IDisposable şablonunu diğer ilginç şeyler için de kullanabilirsiniz (Rhino Mocks'ın kullandığı yolun diğer noktası gibi). Temel olarak, derleyicinin her zaman "kullanılmış" nesneyi çağırması gerçeğinden yararlanabilirsiniz . Belirli bir işlemden sonra gerçekleşmesi gereken bir şey varsa ... kesin bir başlangıç ​​ve bitişe sahip bir şey ... o zaman basitçe işlemi kurucuda başlatan ve sonra Dispose yönteminde biten IDisposable sınıfını yapabilirsiniz.

Bu, söz konusu işlemin açık başlangıcını ve sonunu belirtmek için gerçekten güzel bir sözdizimi kullanmanızı sağlar. System.Transactions işi de böyle çalışır.


3

ADO.NET kullanırken bağlantı nesnesi veya okuyucu nesnesi gibi şeyler için anahtar çalışmasını kullanabilirsiniz. Bu şekilde kod bloğu tamamlandığında bağlantınız otomatik olarak imha edilir.


2
Sadece kod bloğunun tamamlanması gerekmediğini de ekleyeceğim. Kullanım bloğu, işlenmeyen bir istisna durumunda bile kaynağı atacaktır.
harpo

Sadece başka hiç emin Toplayıcı siz istediğiniz için ayırmaları ilgilenir Çöp yapma yerine zaman bunu yapmanın bir yolu, açıklık o istiyor.
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 
            }
    }

2

using , kullanıldıktan sonra atılmasını istediğiniz bir kaynağınız olduğunda kullanılır.

Örneğin, bir Dosya kaynağı tahsis ediyorsanız ve küçük bir okuma veya yazma için kodun yalnızca bir bölümünde kullanmanız gerekiyorsa, kullanma işlemi biter bitmez Dosya kaynağının atılması için kullanışlıdır.

Kullanılan kaynağın düzgün çalışması için IDisposable uygulaması gerekir.

Misal:

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

1

Using anahtar sözcüğü, nesnenin kapsamını tanımlar ve kapsam tamamlandığında nesneyi atar. Örneğin.

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

Anahtar kelimeyi C # kullanarak MSDN makalesi için buraya bakın .


1

Son derece önemli olduğu için değil, aynı zamanda kaynakları anında değiştirmek için de kullanılabilir. Evet, daha önce de belirtildiği gibi tek kullanımlıktır, ancak belki de özellikle yürütme işleminizin geri kalanında diğer kaynaklarla uyumsuz oldukları kaynakları istemezsiniz. Yani başka yere müdahale etmeyecek şekilde atmak istiyorsunuz.


1

Aşağıdaki yorumlar sayesinde, bu yazıyı biraz temizleyeceğim (o zaman 'çöp toplama' kelimelerini
kullanmamalıydım , özür dilerim): Kullanırken, nesnede Dispose () yöntemini çağırır kullanım kapsamının sonunda. Böylece Dispose () yönteminizde oldukça büyük bir temizleme koduna sahip olabilirsiniz.
Umarım bu işaretlenmemiş olabilir bir madde işareti: IDisposable uygularsanız, Dispose () uygulamanızda GC.SuppressFinalize () 'i çağırdığınızdan emin olun, aksi takdirde otomatik çöp toplama gelip bazılarında Sonlandırmaya çalışır zaten imha ettiyseniz en azından kaynak israfı olacaktır.


Dolaylı bir etkisi vardır. Nesneyi açıkça bertaraf ettiğiniz için, sonlandırma gerektirmez ve bu nedenle daha önce GC olabilir.
Kent Boogaart

1

Nesnenin hemen atıldığı makul bir kullanımın başka bir örneği:

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);
    }
}

1

Kıvırcık parantezlerin dışındaki her şey atılır, bu nedenle nesnelerinizi kullanmıyorsanız atmak harikadır. SqlDataAdapter nesneniz varsa ve uygulama yaşam döngüsünde yalnızca bir kez kullanıyorsanız ve yalnızca bir veri kümesini dolduruyorsanız ve artık buna ihtiyacınız yoksa, kodu kullanabilirsiniz:

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

1

Using ifadesi, IDisposable nesneleri doğru kullanmak için bir kolaylık mekanizması sağlar. Kural olarak, IDisposable nesnesini kullandığınızda, bunu bir using deyiminde bildirmeli ve başlatmalısınız. Using ifadesi, nesne üzerindeki Dispose yöntemini doğru şekilde çağırır ve (daha önce gösterildiği gibi kullandığınızda), Dispose çağrılır çağrılmadığında nesnenin kendisinin kapsam dışına çıkmasına da neden olur. Kullanım bloğunda, nesne salt okunurdur ve değiştirilemez veya yeniden atanamaz.

Bu buradan geliyor:


1

Benim için "using" adı biraz kafa karıştırıcı, çünkü bir Namespace veya bir ifadeyi (burada tartışılan gibi) hata işleme için içe aktarmak için bir direktif olabilir.

Hata işleme için farklı bir isim iyi olurdu ve belki bir şekilde daha açık bir isim olurdu.


1

Örnek için kapsam oluşturmak için de kullanılabilir:

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);
          }
      }
   }

}

1

Using ifadesi, .NET'e artık gerekli olmadığında using blokunda belirtilen nesneyi bırakmasını söyler. Bu nedenle, System.IO Türleri gibi, onlardan sonra temizlenmesi gereken sınıflar için 'using' bloğunu kullanmalısınız.


1

usingAnahtar kelimenin C # içinde aşağıdaki gibi iki kullanımı vardır .

  1. Direktif olarak

    Genel olarak, usingarka plan kod ve sınıf dosyalarına ad alanları eklemek için anahtar kelimeyi kullanırız . Ardından tüm sınıfları, arayüzleri ve soyut sınıfları ve bunların mevcut sayfadaki yöntemlerini ve özelliklerini kullanılabilir hale getirir.

    Misal:

    using System.IO;
  2. Bir açıklama olarak

    Bu, usinganahtar kelimeyi C # 'da kullanmanın başka bir yoludur . Çöp Toplama'daki performansı iyileştirmede hayati bir rol oynar.

    usingDispose ifadesi olmasını sağlar () nesneleri oluşturma ve yöntemleri, özellikleri çağıran ve benzeri olduğunda bir durum meydana gelse bile denir. Dispose (), özel Çöp Toplama'nın uygulanmasına yardımcı olan IDisposable arabiriminde bulunan bir yöntemdir. Başka bir deyişle, bazı veritabanı işlemi (Ekle, Güncelleştir, Sil) yapıyorum ama bir şekilde bir istisna oluşursa, burada using deyimi bağlantıyı otomatik olarak kapatır. Bağlantı Close () yöntemini açıkça çağırmanıza gerek yoktur.

    Bir diğer önemli faktör ise Bağlantı Havuzu Oluşturmada yardımcı olmasıdır. .NET'te Bağlantı Havuzu Oluşturma, bir veritabanı bağlantısının birden çok kez kapatılmasını önlemeye yardımcı olur. Bağlantı nesnesini ileride kullanmak üzere bir havuza gönderir (sonraki veritabanı çağrısı). Uygulamanızdan bir sonraki veritabanı bağlantısı çağrıldığında, bağlantı havuzu havuzdaki kullanılabilir nesneleri getirir. Böylece uygulamanın performansını artırmaya yardımcı olur. Using ifadesini kullandığımızda, denetleyici nesneyi bağlantı havuzuna otomatik olarak gönderir, Close () ve Dispose () yöntemlerini açıkça çağırmaya gerek yoktur.

    Try-catch bloğunu kullanarak using deyiminin yaptığıyla aynı şeyi yapabilir ve nihayet blok içinde açıkça Dispose () öğesini çağırabilirsiniz. Ancak using ifadesi, kodu daha temiz ve daha zarif hale getirmek için çağrıları otomatik olarak yapar. Kullanım bloğunda, nesne salt okunurdur ve değiştirilemez veya yeniden atanamaz.

    Misal:

    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));
          }
    }

Önceki kodda herhangi bir bağlantıyı kapatmıyorum; otomatik olarak kapanacaktır. usingİfadesi nedeniyle otomatik) conn.Close (arayacak usingdeyimi ( using (SqlConnection conn = new SqlConnection(connString)) ve bir SqlDataReader nesnesi için aynı. Ayrıca herhangi bir istisna oluşursa bağlantı otomatik olarak kapanır.

Daha fazla bilgi için, bkz . C # 'da Kullanmanın Kullanımı ve Önemi .



-1

deyim olarak kullanıldığında, belirtilen nesneye otomatik olarak atama çağrılır. Nesne, IDisposable arabirimini uygulamalıdır. Bir ifadede aynı türden olduğu sürece birkaç nesne kullanmak mümkündür.

CLR kodunuzu MSIL'e dönüştürür. Using ifadesi denemeye dönüştürülür ve sonunda engellenir. Using ifadesi IL'de bu şekilde temsil edilir. Using ifadesi üç bölüme çevrilir: edinme, kullanma ve elden çıkarma. Kaynak önce edinilir, daha sonra kullanım son olarak bir cümle ile bir try deyimine eklenir. Nesne daha sonra nihayet fıkrasında yer alır.


-3

Belirli bir değişkenin kapsamını tanımlamak için Cümle Kullanımı kullanılır. Örneğin:

     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.
            }

Bu, nesneleri atmak için birini yanlış yönlendirebilir. Belki bunu kod bloğu ile karıştırıyorsunuz, bir değişkenin kapsamını sınırlamak istiyorsanız bunun için iç içe kod bloğu kullanabilirsiniz: public static void Main (params string [] args) {{// nested code block}}
luiseduardohd
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.